diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm deleted file mode 100644 index 82c7c5e77..000000000 --- a/lib/Slic3r/GUI.pm +++ /dev/null @@ -1,337 +0,0 @@ -package Slic3r::GUI; -use strict; -use warnings; -use utf8; - -use File::Basename qw(basename); -use FindBin; -use List::Util qw(first); -use Slic3r::GUI::MainFrame; -use Slic3r::GUI::Plater; -use Slic3r::GUI::Plater::3D; -use Slic3r::GUI::Plater::3DPreview; - -use Wx::Locale gettext => 'L'; - -our $have_OpenGL = eval "use Slic3r::GUI::3DScene; 1"; - -use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow :filedialog :font); -use Wx::Event qw(EVT_IDLE EVT_COMMAND EVT_MENU); -use base 'Wx::App'; - -use constant FILE_WILDCARDS => { - known => 'Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.zip.amf;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA', - stl => 'STL files (*.stl)|*.stl;*.STL', - obj => 'OBJ files (*.obj)|*.obj;*.OBJ', - amf => 'AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML', - threemf => '3MF files (*.3mf)|*.3mf;*.3MF', - prusa => 'Prusa Control files (*.prusa)|*.prusa;*.PRUSA', - ini => 'INI files *.ini|*.ini;*.INI', - gcode => 'G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC', -}; -use constant MODEL_WILDCARD => join '|', @{&FILE_WILDCARDS}{qw(known stl obj amf threemf prusa)}; - -# Datadir provided on the command line. -our $datadir; -our $no_plater; -our @cb; - -our $small_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); -$small_font->SetPointSize(11) if &Wx::wxMAC; -our $small_bold_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); -$small_bold_font->SetPointSize(11) if &Wx::wxMAC; -$small_bold_font->SetWeight(wxFONTWEIGHT_BOLD); -our $medium_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); -$medium_font->SetPointSize(12); -our $grey = Wx::Colour->new(200,200,200); - -# Events to be sent from a C++ menu implementation: -# 1) To inform about a change of the application language. -our $LANGUAGE_CHANGE_EVENT = Wx::NewEventType; -# 2) To inform about a change of Preferences. -our $PREFERENCES_EVENT = Wx::NewEventType; -# To inform AppConfig about Slic3r version available online -our $VERSION_ONLINE_EVENT = Wx::NewEventType; - -sub OnInit { - my ($self) = @_; - - $self->SetAppName('Slic3rPE'); - $self->SetAppDisplayName('Slic3r++'); - Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION; - - # Set the Slic3r data directory at the Slic3r XS module. - # Unix: ~/.Slic3r - # Windows: "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r" - # Mac: "~/Library/Application Support/Slic3r" - Slic3r::set_data_dir($datadir || Wx::StandardPaths::Get->GetUserDataDir); - Slic3r::GUI::set_wxapp($self); - - $self->{app_config} = Slic3r::GUI::AppConfig->new; - Slic3r::GUI::set_app_config($self->{app_config}); - $self->{preset_bundle} = Slic3r::GUI::PresetBundle->new; - Slic3r::GUI::set_preset_bundle($self->{preset_bundle}); - - # just checking for existence of Slic3r::data_dir is not enough: it may be an empty directory - # supplied as argument to --datadir; in that case we should still run the wizard - eval { $self->{preset_bundle}->setup_directories() }; - if ($@) { - warn $@ . "\n"; - fatal_error(undef, $@); - } - my $app_conf_exists = $self->{app_config}->exists; - # load settings - $self->{app_config}->load if $app_conf_exists; - $self->{app_config}->set('version', $Slic3r::VERSION); - $self->{app_config}->save; - - $self->{preset_updater} = Slic3r::PresetUpdater->new($VERSION_ONLINE_EVENT); - Slic3r::GUI::set_preset_updater($self->{preset_updater}); - - Slic3r::GUI::load_language(); - - # Suppress the '- default -' presets. - $self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0); - eval { $self->{preset_bundle}->load_presets($self->{app_config}); }; - if ($@) { - warn $@ . "\n"; - show_error(undef, $@); - } - - # application frame - print STDERR "Creating main frame...\n"; - Wx::Image::FindHandlerType(wxBITMAP_TYPE_PNG) || Wx::Image::AddHandler(Wx::PNGHandler->new); - $self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new( - no_plater => $no_plater, - lang_ch_event => $LANGUAGE_CHANGE_EVENT, - preferences_event => $PREFERENCES_EVENT, - ); - $self->SetTopWindow($frame); - - # This makes CallAfter() work - EVT_IDLE($self->{mainframe}, sub { - while (my $cb = shift @cb) { - $cb->(); - } - $self->{app_config}->save if $self->{app_config}->dirty; - }); - - # On OS X the UI tends to freeze in weird ways if modal dialogs (config wizard, update notifications, ...) - # are shown before or in the same event callback with the main frame creation. - # Therefore we schedule them for later using CallAfter. - $self->CallAfter(sub { - eval { - if (! $self->{preset_updater}->config_update()) { - $self->{mainframe}->Close; - } - }; - if ($@) { - show_error(undef, $@); - $self->{mainframe}->Close; - } - }); - - $self->CallAfter(sub { - if (! Slic3r::GUI::config_wizard_startup($app_conf_exists)) { - # Only notify if there was not wizard so as not to bother too much ... - $self->{preset_updater}->slic3r_update_notify(); - } - $self->{preset_updater}->sync($self->{preset_bundle}); - }); - - # The following event is emited by the C++ menu implementation of application language change. - EVT_COMMAND($self, -1, $LANGUAGE_CHANGE_EVENT, sub{ - print STDERR "LANGUAGE_CHANGE_EVENT\n"; - $self->recreate_GUI; - }); - - # The following event is emited by the C++ menu implementation of preferences change. - EVT_COMMAND($self, -1, $PREFERENCES_EVENT, sub{ - $self->update_ui_from_settings; - }); - - # The following event is emited by PresetUpdater (C++) to inform about - # the newer Slic3r application version avaiable online. - EVT_COMMAND($self, -1, $VERSION_ONLINE_EVENT, sub { - my ($self, $event) = @_; - my $version = $event->GetString; - $self->{app_config}->set('version_online', $version); - $self->{app_config}->save; - }); - - return 1; -} - -sub recreate_GUI{ - print STDERR "recreate_GUI\n"; - my ($self) = @_; - my $topwindow = $self->GetTopWindow(); - $self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new( - no_plater => $no_plater, - lang_ch_event => $LANGUAGE_CHANGE_EVENT, - preferences_event => $PREFERENCES_EVENT, - ); - - if($topwindow) - { - $self->SetTopWindow($frame); - $topwindow->Destroy; - } - - EVT_IDLE($self->{mainframe}, sub { - while (my $cb = shift @cb) { - $cb->(); - } - $self->{app_config}->save if $self->{app_config}->dirty; - }); - - # On OSX the UI was not initialized correctly if the wizard was called - # before the UI was up and running. - $self->CallAfter(sub { - # Run the config wizard, don't offer the "reset user profile" checkbox. - Slic3r::GUI::config_wizard_startup(1); - }); -} - -sub system_info { - my ($self) = @_; - my $slic3r_info = Slic3r::slic3r_info(format => 'html'); - my $copyright_info = Slic3r::copyright_info(format => 'html'); - my $system_info = Slic3r::system_info(format => 'html'); - my $opengl_info; - my $opengl_info_txt = ''; - if (defined($self->{mainframe}) && defined($self->{mainframe}->{plater}) && - defined($self->{mainframe}->{plater}->{canvas3D})) { - $opengl_info = Slic3r::GUI::_3DScene::get_gl_info(1, 1); - $opengl_info_txt = Slic3r::GUI::_3DScene::get_gl_info(0, 1); - } -# my $about = Slic3r::GUI::SystemInfo->new( -# parent => undef, -# slic3r_info => $slic3r_info, -# system_info => $system_info, -# opengl_info => $opengl_info, -# text_info => Slic3r::slic3r_info . Slic3r::system_info . $opengl_info_txt, -# ); -# $about->ShowModal; -# $about->Destroy; -} - -# static method accepting a wxWindow object as first parameter -sub catch_error { - my ($self, $cb, $message_dialog) = @_; - if (my $err = $@) { - $cb->() if $cb; - $message_dialog - ? $message_dialog->($err, 'Error', wxOK | wxICON_ERROR) - : Slic3r::GUI::show_error($self, $err); - return 1; - } - return 0; -} - -# static method accepting a wxWindow object as first parameter -sub show_error { - my ($parent, $message) = @_; - Slic3r::GUI::show_error_id($parent ? $parent->GetId() : 0, $message); -} - -# static method accepting a wxWindow object as first parameter -sub show_info { - my ($parent, $message, $title) = @_; - Wx::MessageDialog->new($parent, $message, $title || 'Notice', wxOK | wxICON_INFORMATION)->ShowModal; -} - -# static method accepting a wxWindow object as first parameter -sub fatal_error { - show_error(@_); - exit 1; -} - -# static method accepting a wxWindow object as first parameter -sub warning_catcher { - my ($self, $message_dialog) = @_; - return sub { - my $message = shift; - return if $message =~ /GLUquadricObjPtr|Attempt to free unreferenced scalar/; - my @params = ($message, 'Warning', wxOK | wxICON_WARNING); - $message_dialog - ? $message_dialog->(@params) - : Wx::MessageDialog->new($self, @params)->ShowModal; - }; -} - -sub notify { - my ($self, $message) = @_; - - my $frame = $self->GetTopWindow; - # try harder to attract user attention on OS X - $frame->RequestUserAttention(&Wx::wxMAC ? wxUSER_ATTENTION_ERROR : wxUSER_ATTENTION_INFO) - unless ($frame->IsActive); - - # There used to be notifier using a Growl application for OSX, but Growl is dead. - # The notifier also supported the Linux X D-bus notifications, but that support was broken. - #TODO use wxNotificationMessage? -} - -# Called after the Preferences dialog is closed and the program settings are saved. -# Update the UI based on the current preferences. -sub update_ui_from_settings { - my ($self) = @_; - $self->{mainframe}->update_ui_from_settings; -} - -sub open_model { - my ($self, $window) = @_; - - my $dlg_title = L('Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):'); - my $dialog = Wx::FileDialog->new($window // $self->GetTopWindow, $dlg_title, - $self->{app_config}->get_last_dir, "", - MODEL_WILDCARD, wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST); - if ($dialog->ShowModal != wxID_OK) { - $dialog->Destroy; - return; - } - my @input_files = $dialog->GetPaths; - $dialog->Destroy; - return @input_files; -} - -sub CallAfter { - my ($self, $cb) = @_; - push @cb, $cb; -} - -sub append_menu_item { - my ($self, $menu, $string, $description, $cb, $id, $icon, $kind) = @_; - - $id //= &Wx::NewId(); - my $item = Wx::MenuItem->new($menu, $id, $string, $description // '', $kind // 0); - $self->set_menu_item_icon($item, $icon); - $menu->Append($item); - - EVT_MENU($self, $id, $cb); - return $item; -} - -sub append_submenu { - my ($self, $menu, $string, $description, $submenu, $id, $icon) = @_; - - $id //= &Wx::NewId(); - my $item = Wx::MenuItem->new($menu, $id, $string, $description // ''); - $self->set_menu_item_icon($item, $icon); - $item->SetSubMenu($submenu); - $menu->Append($item); - - return $item; -} - -sub set_menu_item_icon { - my ($self, $menuItem, $icon) = @_; - - # SetBitmap was not available on OS X before Wx 0.9927 - if ($icon && $menuItem->can('SetBitmap')) { - $menuItem->SetBitmap(Wx::Bitmap->new(Slic3r::var($icon), wxBITMAP_TYPE_PNG)); - } -} - -1; diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm deleted file mode 100644 index 23decaa37..000000000 --- a/lib/Slic3r/GUI/3DScene.pm +++ /dev/null @@ -1,70 +0,0 @@ -# Implements pure perl packages -# -# Slic3r::GUI::3DScene::Base; -# Slic3r::GUI::3DScene; -# -# Slic3r::GUI::Plater::3D derives from Slic3r::GUI::3DScene, -# Slic3r::GUI::Plater::3DPreview, -# Slic3r::GUI::Plater::ObjectCutDialog and Slic3r::GUI::Plater::ObjectPartsPanel -# own $self->{canvas} of the Slic3r::GUI::3DScene type. -# -# Therefore the 3DScene supports renderng of STLs, extrusions and cutting planes, -# and camera manipulation. - -package Slic3r::GUI::3DScene::Base; -use strict; -use warnings; - -use Wx qw(wxTheApp :timer :bitmap :icon :dialog); -# must load OpenGL *before* Wx::GLCanvas -use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants); -use base qw(Wx::GLCanvas Class::Accessor); -use Wx::GLCanvas qw(:all); - -sub new { - my ($class, $parent) = @_; - - # We can only enable multi sample anti aliasing wih wxWidgets 3.0.3 and with a hacked Wx::GLCanvas, - # which exports some new WX_GL_XXX constants, namely WX_GL_SAMPLE_BUFFERS and WX_GL_SAMPLES. - my $can_multisample = - ! wxTheApp->{app_config}->get('use_legacy_opengl') && - Wx::wxVERSION >= 3.000003 && - defined Wx::GLCanvas->can('WX_GL_SAMPLE_BUFFERS') && - defined Wx::GLCanvas->can('WX_GL_SAMPLES'); - my $attrib = [WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24]; - if ($can_multisample) { - # Request a window with multi sampled anti aliasing. This is a new feature in Wx 3.0.3 (backported from 3.1.0). - # Use eval to avoid compilation, if the subs WX_GL_SAMPLE_BUFFERS and WX_GL_SAMPLES are missing. - eval 'push(@$attrib, (WX_GL_SAMPLE_BUFFERS, 1, WX_GL_SAMPLES, 4));'; - } - # wxWidgets expect the attrib list to be ended by zero. - push(@$attrib, 0); - - # we request a depth buffer explicitely because it looks like it's not created by - # default on Linux, causing transparency issues - my $self = $class->SUPER::new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, 0, "", $attrib); - - Slic3r::GUI::_3DScene::add_canvas($self); - Slic3r::GUI::_3DScene::allow_multisample($self, $can_multisample); - - return $self; -} - -sub Destroy { - my ($self) = @_; - Slic3r::GUI::_3DScene::remove_canvas($self); - return $self->SUPER::Destroy; -} - -# The 3D canvas to display objects and tool paths. -package Slic3r::GUI::3DScene; -use base qw(Slic3r::GUI::3DScene::Base); - -sub new { - my $class = shift; - - my $self = $class->SUPER::new(@_); - return $self; -} - -1; diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm deleted file mode 100644 index 4d16356ba..000000000 --- a/lib/Slic3r/GUI/MainFrame.pm +++ /dev/null @@ -1,644 +0,0 @@ -# The main frame, the parent of all. - -package Slic3r::GUI::MainFrame; -use strict; -use warnings; -use utf8; - -use File::Basename qw(basename dirname); -use FindBin; -use List::Util qw(min first); -use Slic3r::Geometry qw(X Y); -use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog :dirdialog - :font :icon wxTheApp); -use Wx::Event qw(EVT_CLOSE EVT_COMMAND EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED); -use base 'Wx::Frame'; - -use Wx::Locale gettext => 'L'; - -our $qs_last_input_file; -our $qs_last_output_file; -our $last_config; -our $appController; - -# Events to be sent from a C++ Tab implementation: -# 1) To inform about a change of a configuration value. -our $VALUE_CHANGE_EVENT = Wx::NewEventType; -# 2) To inform about a preset selection change or a "modified" status change. -our $PRESETS_CHANGED_EVENT = Wx::NewEventType; -# 3) To update the status bar with the progress information. -our $PROGRESS_BAR_EVENT = Wx::NewEventType; -# 4) To display an error dialog box from a thread on the UI thread. -our $ERROR_EVENT = Wx::NewEventType; -# 5) To inform about a change of object selection -our $OBJECT_SELECTION_CHANGED_EVENT = Wx::NewEventType; -# 6) To inform about a change of object settings -our $OBJECT_SETTINGS_CHANGED_EVENT = Wx::NewEventType; -# 7) To inform about a remove of object -our $OBJECT_REMOVE_EVENT = Wx::NewEventType; -# 8) To inform about a update of the scene -our $UPDATE_SCENE_EVENT = Wx::NewEventType; - -sub new { - my ($class, %params) = @_; - - my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE); - Slic3r::GUI::set_main_frame($self); - - $appController = Slic3r::AppController->new(); - - if ($^O eq 'MSWin32') { - # Load the icon either from the exe, or from the ico file. - my $iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe'; - $iconfile = Slic3r::var("Slic3r.ico") unless -f $iconfile; - $self->SetIcon(Wx::Icon->new($iconfile, wxBITMAP_TYPE_ICO)); - } else { - $self->SetIcon(Wx::Icon->new(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG)); - } - - # store input params - $self->{no_plater} = $params{no_plater}; - $self->{loaded} = 0; - $self->{lang_ch_event} = $params{lang_ch_event}; - $self->{preferences_event} = $params{preferences_event}; - - # initialize tabpanel and menubar - $self->_init_tabpanel; - $self->_init_menubar; - - # set default tooltip timer in msec - # SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values - # (SetAutoPop is not available on GTK.) - eval { Wx::ToolTip::SetAutoPop(32767) }; - - # initialize status bar - $self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new(); - $self->{statusbar}->Embed; - $self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/supermerill/slic3r/releases")); - # Make the global status bar and its progress indicator available in C++ - Slic3r::GUI::set_progress_status_bar($self->{statusbar}); - $appController->set_global_progress_indicator($self->{statusbar}); - - $appController->set_model($self->{plater}->{model}); - $appController->set_print($self->{plater}->{print}); - - $self->{plater}->{appController} = $appController; - - $self->{loaded} = 1; - - # initialize layout - { - my $sizer = Wx::BoxSizer->new(wxVERTICAL); - $sizer->Add($self->{tabpanel}, 1, wxEXPAND); - $sizer->SetSizeHints($self); - $self->SetSizer($sizer); - $self->Fit; - $self->SetMinSize([760, 490]); - $self->SetSize($self->GetMinSize); - Slic3r::GUI::restore_window_size($self, "main_frame"); - $self->Show; - $self->Layout; - } - - # declare events - EVT_CLOSE($self, sub { - my (undef, $event) = @_; - if ($event->CanVeto && !Slic3r::GUI::check_unsaved_changes) { - $event->Veto; - return; - } - # save window size - Slic3r::GUI::save_window_size($self, "main_frame"); - # Save the slic3r.ini. Usually the ini file is saved from "on idle" callback, - # but in rare cases it may not have been called yet. - wxTheApp->{app_config}->save; - $self->{statusbar}->ResetCancelCallback(); - $self->{plater}->{print} = undef if($self->{plater}); - Slic3r::GUI::_3DScene::remove_all_canvases(); - Slic3r::GUI::deregister_on_request_update_callback(); - # propagate event - $event->Skip; - }); - - $self->update_ui_from_settings; - - Slic3r::GUI::update_mode(); - - return $self; -} - -sub _init_tabpanel { - my ($self) = @_; - - $self->{tabpanel} = my $panel = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL); - Slic3r::GUI::set_tab_panel($panel); - - EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{tabpanel}, sub { - my $panel = $self->{tabpanel}->GetCurrentPage; - $panel->OnActivate if $panel->can('OnActivate'); - - for my $tab_name (qw(print filament printer)) { - Slic3r::GUI::get_preset_tab("$tab_name")->OnActivate if ("$tab_name" eq $panel->GetName); - } - }); - - if (!$self->{no_plater}) { - $panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel, - event_object_selection_changed => $OBJECT_SELECTION_CHANGED_EVENT, - event_object_settings_changed => $OBJECT_SETTINGS_CHANGED_EVENT, - event_remove_object => $OBJECT_REMOVE_EVENT, - event_update_scene => $UPDATE_SCENE_EVENT, - ), L("Plater")); - } - - #TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view. - # The following event is emited by the C++ Tab implementation on config value change. - EVT_COMMAND($self, -1, $VALUE_CHANGE_EVENT, sub { - my ($self, $event) = @_; - my $str = $event->GetString; - my ($opt_key, $name) = ($str =~ /(.*) (.*)/); - #print "VALUE_CHANGE_EVENT: ", $opt_key, "\n"; - my $tab = Slic3r::GUI::get_preset_tab($name); - my $config = $tab->get_config; - if ($self->{plater}) { - $self->{plater}->on_config_change($config); # propagate config change events to the plater - if ($opt_key eq 'extruders_count'){ - my $value = $event->GetInt(); - $self->{plater}->on_extruders_change($value); - } - if ($opt_key eq 'printer_technology'){ - my $value = $event->GetInt();# 0 ~ "ptFFF"; 1 ~ "ptSLA" - $self->{plater}->show_preset_comboboxes($value); - } - } - # don't save while loading for the first time - $self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded}; - }); - # The following event is emited by the C++ Tab implementation on preset selection, - # or when the preset's "modified" status changes. - EVT_COMMAND($self, -1, $PRESETS_CHANGED_EVENT, sub { - my ($self, $event) = @_; - my $tab_name = $event->GetString; - - my $tab = Slic3r::GUI::get_preset_tab($tab_name); - if ($self->{plater}) { - # Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs. - my $presets = $tab->get_presets; - if (defined $presets){ - my $reload_dependent_tabs = $tab->get_dependent_tabs; - $self->{plater}->update_presets($tab_name, $reload_dependent_tabs, $presets); - $self->{plater}->{"selected_item_$tab_name"} = $tab->get_selected_preset_item; - if ($tab_name eq 'printer') { - # Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors. - for my $tab_name_other (qw(print filament sla_material)) { - # If the printer tells us that the print or filament preset has been switched or invalidated, - # refresh the print or filament tab page. Otherwise just refresh the combo box. - my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs}))) - ? 'load_current_preset' : 'update_tab_ui'; - $self->{options_tabs}{$tab_name_other}->$update_action; - } - } - $self->{plater}->on_config_change($tab->get_config); - } - } - }); - - # The following event is emited by the C++ Tab implementation on object selection change. - EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub { - my ($self, $event) = @_; - my $obj_idx = $event->GetId; -# my $child = $event->GetInt == 1 ? 1 : undef; -# $self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child); -# $self->{plater}->item_changed_selection($obj_idx); - - my $vol_idx = $event->GetInt; - $self->{plater}->select_object_from_cpp($obj_idx < 0 ? undef: $obj_idx, $vol_idx<0 ? -1 : $vol_idx); - }); - - # The following event is emited by the C++ GUI implementation on object settings change. - EVT_COMMAND($self, -1, $OBJECT_SETTINGS_CHANGED_EVENT, sub { - my ($self, $event) = @_; - - my $line = $event->GetString; - my ($obj_idx, $parts_changed, $part_settings_changed) = split('',$line); - - $self->{plater}->changed_object_settings($obj_idx, $parts_changed, $part_settings_changed); - }); - - # The following event is emited by the C++ GUI implementation on object remove. - EVT_COMMAND($self, -1, $OBJECT_REMOVE_EVENT, sub { - my ($self, $event) = @_; - $self->{plater}->remove(); - }); - - # The following event is emited by the C++ GUI implementation on extruder change for object. - EVT_COMMAND($self, -1, $UPDATE_SCENE_EVENT, sub { - my ($self, $event) = @_; - $self->{plater}->update(); - }); - - Slic3r::GUI::create_preset_tabs($VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT); - $self->{options_tabs} = {}; - for my $tab_name (qw(print filament sla_material printer)) { - $self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name"); - } - - # Update progress bar with an event sent by the slicing core. - EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub { - my ($self, $event) = @_; - if (defined $self->{progress_dialog}) { - # If a progress dialog is open, update it. - $self->{progress_dialog}->Update($event->GetInt, $event->GetString . "…"); - } else { - # Otherwise update the main window status bar. - $self->{statusbar}->SetProgress($event->GetInt); - $self->{statusbar}->SetStatusText($event->GetString . "…"); - } - }); - - EVT_COMMAND($self, -1, $ERROR_EVENT, sub { - my ($self, $event) = @_; - Slic3r::GUI::show_error($self, $event->GetString); - }); - - if ($self->{plater}) { - $self->{plater}->on_select_preset(sub { - my ($group, $name) = @_; - $self->{options_tabs}{$group}->select_preset($name); - }); - # load initial config - my $full_config = wxTheApp->{preset_bundle}->full_config; - $self->{plater}->on_config_change($full_config); - - # Show a correct number of filament fields. - if (defined $full_config->nozzle_diameter){ # nozzle_diameter is undefined when SLA printer is selected - $self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter})); - } - - # Show correct preset comboboxes according to the printer_technology - $self->{plater}->show_preset_comboboxes(($full_config->printer_technology eq "FFF") ? 0 : 1); - } -} - -sub _init_menubar { - my ($self) = @_; - - # File menu - my $fileMenu = Wx::Menu->new; - { - wxTheApp->append_menu_item($fileMenu, L("Open STL/OBJ/AMF/3MF…\tCtrl+O"), L('Open a model'), sub { - $self->{plater}->add if $self->{plater}; - }, undef, undef); #'brick_add.png'); - $self->_append_menu_item($fileMenu, L("&Load Config…\tCtrl+L"), L('Load exported configuration file'), sub { - $self->load_config_file; - }, undef, 'plugin_add.png'); - $self->_append_menu_item($fileMenu, L("&Export Config…\tCtrl+E"), L('Export current configuration to file'), sub { - $self->export_config; - }, undef, 'plugin_go.png'); - $self->_append_menu_item($fileMenu, L("&Load Config Bundle…"), L('Load presets from a bundle'), sub { - $self->load_configbundle; - }, undef, 'lorry_add.png'); - $self->_append_menu_item($fileMenu, L("&Export Config Bundle…"), L('Export all presets to file'), sub { - $self->export_configbundle; - }, undef, 'lorry_go.png'); - $fileMenu->AppendSeparator(); - $self->_append_menu_item($fileMenu, L("Slice to PNG…"), L('Slice file to a set of PNG files'), sub { - $self->slice_to_png; - }, undef, 'shape_handles.png'); - $self->{menu_item_reslice_now} = $self->_append_menu_item( - $fileMenu, L("(&Re)Slice Now\tCtrl+S"), L('Start new slicing process'), - sub { $self->reslice_now; }, undef, 'shape_handles.png'); - $fileMenu->AppendSeparator(); - $self->_append_menu_item($fileMenu, L("Repair STL file…"), L('Automatically repair an STL file'), sub { - $self->repair_stl; - }, undef, 'wrench.png'); - $fileMenu->AppendSeparator(); - $self->_append_menu_item($fileMenu, L("&Quit"), L('Quit Slic3r'), sub { - $self->Close(0); - }, wxID_EXIT); - } - - # Plater menu - unless ($self->{no_plater}) { - my $plater = $self->{plater}; - - $self->{plater_menu} = Wx::Menu->new; - $self->_append_menu_item($self->{plater_menu}, L("Export G-code..."), L('Export current plate as G-code'), sub { - $plater->export_gcode; - }, undef, 'cog_go.png'); - $self->_append_menu_item($self->{plater_menu}, L("Export plate as STL..."), L('Export current plate as STL'), sub { - $plater->export_stl; - }, undef, 'brick_go.png'); - $self->_append_menu_item($self->{plater_menu}, L("Export plate as AMF..."), L('Export current plate as AMF'), sub { - $plater->export_amf; - }, undef, 'brick_go.png'); - $self->_append_menu_item($self->{plater_menu}, L("Export plate as 3MF..."), L('Export current plate as 3MF'), sub { - $plater->export_3mf; - }, undef, 'brick_go.png'); - - $self->{object_menu} = $self->{plater}->object_menu; - $self->on_plater_selection_changed(0); - } - - # Window menu - my $windowMenu = Wx::Menu->new; - { - my $tab_offset = 0; - if (!$self->{no_plater}) { - $self->_append_menu_item($windowMenu, L("Select &Plater Tab\tCtrl+1"), L('Show the plater'), sub { - $self->select_tab(0); - }, undef, 'application_view_tile.png'); - $tab_offset += 1; - } - if (!$self->{no_controller}) { - $self->_append_menu_item($windowMenu, L("Select &Controller Tab\tCtrl+T"), L('Show the printer controller'), sub { - $self->select_tab(1); - }, undef, 'printer_empty.png'); - $tab_offset += 1; - } - if ($tab_offset > 0) { - $windowMenu->AppendSeparator(); - } - $self->_append_menu_item($windowMenu, L("Select P&rint Settings Tab\tCtrl+2"), L('Show the print settings'), sub { - $self->select_tab($tab_offset+0); - }, undef, 'cog.png'); - $self->_append_menu_item($windowMenu, L("Select &Filament Settings Tab\tCtrl+3"), L('Show the filament settings'), sub { - $self->select_tab($tab_offset+1); - }, undef, 'spool.png'); - $self->_append_menu_item($windowMenu, L("Select Print&er Settings Tab\tCtrl+4"), L('Show the printer settings'), sub { - $self->select_tab($tab_offset+2); - }, undef, 'printer_empty.png'); - } - - # View menu - if (!$self->{no_plater}) { - $self->{viewMenu} = Wx::Menu->new; - # \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators, - # as the simple numeric accelerators spoil all numeric data entry. - # The camera control accelerators are captured by 3DScene Perl module instead. - my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] }; - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Iso'), '0'), L('Iso View') , sub { $self->select_view('iso' ); }); - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Top'), '1'), L('Top View') , sub { $self->select_view('top' ); }); - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Bottom'), '2'), L('Bottom View') , sub { $self->select_view('bottom' ); }); - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Front'), '3'), L('Front View') , sub { $self->select_view('front' ); }); - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Rear'), '4'), L('Rear View') , sub { $self->select_view('rear' ); }); - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Left'), '5'), L('Left View') , sub { $self->select_view('left' ); }); - $self->_append_menu_item($self->{viewMenu}, $accel->(L('Right'), '6'), L('Right View') , sub { $self->select_view('right' ); }); - } - - # Help menu - my $helpMenu = Wx::Menu->new; - { - - - - $self->_append_menu_item($helpMenu, L("Slic3r++ Releases"), L('Open the Slic3r++ releases page in your browser'), sub { - Wx::LaunchDefaultBrowser('http://github.com/supermerill/slic3r/releases'); - }); -# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub { -# wxTheApp->check_version(1); -# }); -# $versioncheck->Enable(wxTheApp->have_version_check); - $self->_append_menu_item($helpMenu, L("Slic3r &Website"), L('Open the Slic3r website in your browser'), sub { - Wx::LaunchDefaultBrowser('http://slic3r.org/'); - }); - $self->_append_menu_item($helpMenu, L("Slic3r &Manual"), L('Open the Slic3r manual in your browser'), sub { - Wx::LaunchDefaultBrowser('http://manual.slic3r.org/'); - }); - $helpMenu->AppendSeparator(); - $self->_append_menu_item($helpMenu, L("System Info"), L('Show system information'), sub { - wxTheApp->system_info; - }); - $self->_append_menu_item($helpMenu, L("Show &Configuration Folder"), L('Show user configuration folder (datadir)'), sub { - Slic3r::GUI::desktop_open_datadir_folder(); - }); - $self->_append_menu_item($helpMenu, L("Report an Issue"), L('Report an issue on the Slic3r++ github'), sub { - Wx::LaunchDefaultBrowser('http://github.com/supermerill/slic3r/issues/new'); - }); - $self->_append_menu_item($helpMenu, L("&About Slic3r"), L('Show about dialog'), sub { - Slic3r::GUI::about; - }); - } - - # menubar - # assign menubar to frame after appending items, otherwise special items - # will not be handled correctly - { - my $menubar = Wx::MenuBar->new; - $menubar->Append($fileMenu, L("&File")); - $menubar->Append($self->{plater_menu}, L("&Plater")) if $self->{plater_menu}; - $menubar->Append($self->{object_menu}, L("&Object")) if $self->{object_menu}; - $menubar->Append($windowMenu, L("&Window")); - $menubar->Append($self->{viewMenu}, L("&View")) if $self->{viewMenu}; - # Add additional menus from C++ - Slic3r::GUI::add_menus($menubar, $self->{preferences_event}, $self->{lang_ch_event}); - $menubar->Append($helpMenu, L("&Help")); - $self->SetMenuBar($menubar); - } -} - -sub is_loaded { - my ($self) = @_; - return $self->{loaded}; -} - -# Selection of a 3D object changed on the platter. -sub on_plater_selection_changed { - my ($self, $have_selection) = @_; - return if !defined $self->{object_menu}; - $self->{object_menu}->Enable($_->GetId, $have_selection) - for $self->{object_menu}->GetMenuItems; -} - -sub slice_to_png { - my $self = shift; - $self->{plater}->stop_background_process; - $self->{plater}->async_apply_config; - $appController->print_ctl()->slice_to_png(); -} - -sub reslice_now { - my ($self) = @_; - $self->{plater}->reslice if $self->{plater}; -} - -sub repair_stl { - my $self = shift; - - my $input_file; - { - my $dialog = Wx::FileDialog->new($self, L('Select the STL file to repair:'), - wxTheApp->{app_config}->get_last_dir, "", - &Slic3r::GUI::FILE_WILDCARDS->{stl}, wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if ($dialog->ShowModal != wxID_OK) { - $dialog->Destroy; - return; - } - $input_file = $dialog->GetPaths; - $dialog->Destroy; - } - - my $output_file = $input_file; - { - $output_file =~ s/\.[sS][tT][lL]$/_fixed.obj/; - my $dlg = Wx::FileDialog->new($self, L("Save OBJ file (less prone to coordinate errors than STL) as:"), dirname($output_file), - basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{obj}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if ($dlg->ShowModal != wxID_OK) { - $dlg->Destroy; - return undef; - } - $output_file = $dlg->GetPath; - $dlg->Destroy; - } - - my $tmesh = Slic3r::TriangleMesh->new; - $tmesh->ReadSTLFile($input_file); - $tmesh->repair; - $tmesh->WriteOBJFile($output_file); - Slic3r::GUI::show_info($self, L("Your file was repaired."), L("Repair")); -} - -sub export_config { - my $self = shift; - # Generate a cummulative configuration for the selected print, filaments and printer. - my $config = wxTheApp->{preset_bundle}->full_config(); - # Validate the cummulative configuration. - eval { $config->validate; }; - Slic3r::GUI::catch_error($self) and return; - # Ask user for the file name for the config file. - my $dlg = Wx::FileDialog->new($self, L('Save configuration as:'), - $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir, - $last_config ? basename($last_config) : "config.ini", - &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef; - $dlg->Destroy; - if (defined $file) { - wxTheApp->{app_config}->update_config_dir(dirname($file)); - $last_config = $file; - $config->save($file); - } -} - -# Load a config file containing a Print, Filament & Printer preset. -sub load_config_file { - my ($self, $file) = @_; - if (!$file) { - return unless Slic3r::GUI::check_unsaved_changes; - my $dlg = Wx::FileDialog->new($self, L('Select configuration to load:'), - $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir, - "config.ini", - 'INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g', wxFD_OPEN | wxFD_FILE_MUST_EXIST); - return unless $dlg->ShowModal == wxID_OK; - $file = $dlg->GetPaths; - $dlg->Destroy; - } - eval { wxTheApp->{preset_bundle}->load_config_file($file); }; - # Dont proceed further if the config file cannot be loaded. - return if Slic3r::GUI::catch_error($self); - $_->load_current_preset for (values %{$self->{options_tabs}}); - wxTheApp->{app_config}->update_config_dir(dirname($file)); - $last_config = $file; -} - -sub export_configbundle { - my ($self) = @_; - return unless Slic3r::GUI::check_unsaved_changes; - # validate current configuration in case it's dirty - eval { wxTheApp->{preset_bundle}->full_config->validate; }; - Slic3r::GUI::catch_error($self) and return; - # Ask user for a file name. - my $dlg = Wx::FileDialog->new($self, L('Save presets bundle as:'), - $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir, - "Slic3r_config_bundle.ini", - &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef; - $dlg->Destroy; - if (defined $file) { - # Export the config bundle. - wxTheApp->{app_config}->update_config_dir(dirname($file)); - eval { wxTheApp->{preset_bundle}->export_configbundle($file); }; - Slic3r::GUI::catch_error($self) and return; - } -} - -# Loading a config bundle with an external file name used to be used -# to auto-install a config bundle on a fresh user account, -# but that behavior was not documented and likely buggy. -sub load_configbundle { - my ($self, $file, $reset_user_profile) = @_; - return unless Slic3r::GUI::check_unsaved_changes; - if (!$file) { - my $dlg = Wx::FileDialog->new($self, L('Select configuration to load:'), - $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir, - "config.ini", - &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_OPEN | wxFD_FILE_MUST_EXIST); - return unless $dlg->ShowModal == wxID_OK; - $file = $dlg->GetPaths; - $dlg->Destroy; - } - - wxTheApp->{app_config}->update_config_dir(dirname($file)); - - my $presets_imported = 0; - eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file); }; - Slic3r::GUI::catch_error($self) and return; - - # Load the currently selected preset into the GUI, update the preset selection box. - foreach my $tab (values %{$self->{options_tabs}}) { - $tab->load_current_preset; - } - - my $message = sprintf L("%d presets successfully imported."), $presets_imported; - Slic3r::GUI::show_info($self, $message); -} - -# Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset. -# Also update the platter with the new presets. -sub load_config { - my ($self, $config) = @_; - $_->load_config($config) foreach values %{$self->{options_tabs}}; - $self->{plater}->on_config_change($config) if $self->{plater}; -} - -sub select_tab { - my ($self, $tab) = @_; - $self->{tabpanel}->SetSelection($tab); -} - -# Set a camera direction, zoom to all objects. -sub select_view { - my ($self, $direction) = @_; - if (! $self->{no_plater}) { - $self->{plater}->select_view($direction); - } -} - -sub _append_menu_item { - my ($self, $menu, $string, $description, $cb, $id, $icon) = @_; - $id //= &Wx::NewId(); - my $item = $menu->Append($id, $string, $description); - $self->_set_menu_item_icon($item, $icon); - EVT_MENU($self, $id, $cb); - return $item; -} - -sub _set_menu_item_icon { - my ($self, $menuItem, $icon) = @_; - # SetBitmap was not available on OS X before Wx 0.9927 - if ($icon && $menuItem->can('SetBitmap')) { - $menuItem->SetBitmap(Wx::Bitmap->new(Slic3r::var($icon), wxBITMAP_TYPE_PNG)); - } -} - -# Called after the Preferences dialog is closed and the program settings are saved. -# Update the UI based on the current preferences. -sub update_ui_from_settings { - my ($self) = @_; - $self->{menu_item_reslice_now}->Enable(! wxTheApp->{app_config}->get("background_processing")); - $self->{plater}->update_ui_from_settings if ($self->{plater}); - for my $tab_name (qw(print filament printer)) { - $self->{options_tabs}{$tab_name}->update_ui_from_settings; - } -} - -1; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm deleted file mode 100644 index db360c811..000000000 --- a/lib/Slic3r/GUI/Plater.pm +++ /dev/null @@ -1,2683 +0,0 @@ -# The "Plater" tab. It contains the "3D", "2D", "Preview" and "Layers" subtabs. - -package Slic3r::GUI::Plater; -use strict; -use warnings; -use utf8; - -use File::Basename qw(basename dirname); -use List::Util qw(sum first max); -use Slic3r::Geometry qw(X Y Z scale unscale deg2rad rad2deg); -use Wx qw(:button :colour :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc - :panel :sizer :toolbar :window wxTheApp :notebook :combobox wxNullBitmap); -use Wx::Event qw(EVT_BUTTON EVT_TOGGLEBUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED - EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_LEFT_DOWN EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL - EVT_CHOICE EVT_COMBOBOX EVT_TIMER EVT_NOTEBOOK_PAGE_CHANGED); -use Slic3r::Geometry qw(PI); -use base 'Wx::Panel'; - -use constant TB_ADD => &Wx::NewId; -use constant TB_REMOVE => &Wx::NewId; -use constant TB_RESET => &Wx::NewId; -use constant TB_ARRANGE => &Wx::NewId; -use constant TB_EXPORT_GCODE => &Wx::NewId; -use constant TB_EXPORT_STL => &Wx::NewId; -use constant TB_MORE => &Wx::NewId; -use constant TB_FEWER => &Wx::NewId; -use constant TB_45CW => &Wx::NewId; -use constant TB_45CCW => &Wx::NewId; -use constant TB_SCALE => &Wx::NewId; -use constant TB_SPLIT => &Wx::NewId; -use constant TB_CUT => &Wx::NewId; -use constant TB_SETTINGS => &Wx::NewId; -use constant TB_LAYER_EDITING => &Wx::NewId; - -use Wx::Locale gettext => 'L'; - -# Emitted from the worker thread when the G-code export is finished. -our $SLICING_COMPLETED_EVENT = Wx::NewEventType; -our $PROCESS_COMPLETED_EVENT = Wx::NewEventType; - -my $PreventListEvents = 0; -our $appController; - -# XXX: VK: done, except callback handling and timer -sub new { - my ($class, $parent, %params) = @_; - my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - Slic3r::GUI::set_plater($self); - $self->{config} = Slic3r::Config::new_from_defaults_keys([qw( - bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height - serial_port serial_speed host_type print_host printhost_apikey printhost_cafile - nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width - wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model - )]); - - # store input params - $self->{event_object_selection_changed} = $params{event_object_selection_changed}; - $self->{event_object_settings_changed} = $params{event_object_settings_changed}; - $self->{event_remove_object} = $params{event_remove_object}; - $self->{event_update_scene} = $params{event_update_scene}; - - # C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm - $self->{model} = Slic3r::Model->new; - # C++ Slic3r::Print with Perl extensions in Slic3r/Print.pm - $self->{print} = Slic3r::Print->new; - # List of Perl objects Slic3r::GUI::Plater::Object, representing a 2D preview of the platter. - $self->{objects} = []; - $self->{gcode_preview_data} = Slic3r::GCode::PreviewData->new; - $self->{background_slicing_process} = Slic3r::GUI::BackgroundSlicingProcess->new; - $self->{background_slicing_process}->set_print($self->{print}); - $self->{background_slicing_process}->set_gcode_preview_data($self->{gcode_preview_data}); - $self->{background_slicing_process}->set_sliced_event($SLICING_COMPLETED_EVENT); - $self->{background_slicing_process}->set_finished_event($PROCESS_COMPLETED_EVENT); - - # The C++ slicing core will post a wxCommand message to the main window. - Slic3r::GUI::set_print_callback_event($self->{print}, $Slic3r::GUI::MainFrame::PROGRESS_BAR_EVENT); - - # Initialize preview notebook - $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [-1,335], wxNB_BOTTOM); - - # Initialize handlers for canvases - my $on_select_object = sub { - my ($obj_idx, $vol_idx) = @_; - - if (($obj_idx != -1) && ($vol_idx == -1)) { - # Ignore the special objects (the wipe tower proxy and such). - $self->select_object((defined($obj_idx) && $obj_idx >= 0 && $obj_idx < 1000) ? $obj_idx : undef); - $self->item_changed_selection($obj_idx) if (defined($obj_idx)); - } - }; - my $on_right_click = sub { - my ($canvas, $click_pos_x, $click_pos_y) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $menu = $self->object_menu; - $canvas->PopupMenu($menu, $click_pos_x, $click_pos_y); - $menu->Destroy; - }; - my $on_instances_moved = sub { - $self->update; - }; - - # callback to enable/disable action buttons - my $enable_action_buttons = sub { - my ($enable) = @_; - Slic3r::GUI::enable_action_buttons($enable); -# $self->{btn_export_gcode}->Enable($enable); -# $self->{btn_reslice}->Enable($enable); -# $self->{btn_print}->Enable($enable); -# $self->{btn_send_gcode}->Enable($enable); - }; - - # callback to react to gizmo scale - my $on_gizmo_scale_uniformly = sub { - my ($scale) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - $self->stop_background_process; - - my $variation = $scale / $model_instance->scaling_factor; - #FIXME Scale the layer height profile? - foreach my $range (@{ $model_object->layer_height_ranges }) { - $range->[0] *= $variation; - $range->[1] *= $variation; - } - $_->set_scaling_factor($scale) for @{ $model_object->instances }; - - # Set object scale on c++ side -# Slic3r::GUI::set_object_scale($obj_idx, $model_object->instances->[0]->scaling_factor * 100); - -# $object->transform_thumbnail($self->{model}, $obj_idx); - - #update print and start background processing - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed(1); # refresh info (size, volume etc.) - $self->update; - $self->schedule_background_process; - }; - - # callback to react to gizmo scale - my $on_gizmo_scale_3D = sub { - my ($scale_x, $scale_y, $scale_z) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - $self->stop_background_process; - - #FIXME Scale the layer height profile? -# my $variation = $scale / $model_instance->scaling_factor; -# foreach my $range (@{ $model_object->layer_height_ranges }) { -# $range->[0] *= $variation; -# $range->[1] *= $variation; -# } - - my $scale = Slic3r::Pointf3->new($scale_x, $scale_y, $scale_z); - foreach my $inst (@{ $model_object->instances }) { - $inst->set_scaling_factors($scale); - } - Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); - - #update print and start background processing - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed(1); # refresh info (size, volume etc.) - $self->update; - $self->schedule_background_process; - - }; - - # callback to react to gizmo rotate - my $on_gizmo_rotate = sub { - my ($angle) = @_; - $self->rotate(rad2deg($angle), Z, 'absolute'); - }; - - # callback to react to gizmo rotate - my $on_gizmo_rotate_3D = sub { - my ($angle_x, $angle_y, $angle_z) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - $self->stop_background_process; - - my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z); - foreach my $inst (@{ $model_object->instances }) { - $inst->set_rotations($rotation); - } - Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); - - # update print and start background processing - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed; # refresh info (size etc.) - $self->update; - $self->schedule_background_process; - }; - - # callback to react to gizmo flatten - my $on_gizmo_flatten = sub { - my ($angle, $axis_x, $axis_y, $axis_z) = @_; - $self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0; - }; - - # callback to react to gizmo flatten - my $on_gizmo_flatten_3D = sub { - my ($angle_x, $angle_y, $angle_z) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - $self->stop_background_process; - - my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z); - foreach my $inst (@{ $model_object->instances }) { - $inst->set_rotations($rotation); - } - Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); - - # update print and start background processing - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed; # refresh info (size etc.) - $self->update; - $self->schedule_background_process; - }; - - # callback to update object's geometry info while using gizmos - my $on_update_geometry_info = sub { - my ($size_x, $size_y, $size_z, $scale_factor) = @_; - - my ($obj_idx, $object) = $self->selected_object; - - if ((defined $obj_idx) && ($self->{object_info_size})) { # have we already loaded the info pane? - $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", $size_x, $size_y, $size_z)); - my $model_object = $self->{model}->objects->[$obj_idx]; - if (my $stats = $model_object->mesh_stats) { - $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * $scale_factor**3)); - } - } - }; - - # callback to update object's geometry info while using gizmos - my $on_update_geometry_3D_info = sub { - my ($size_x, $size_y, $size_z, $scale_x, $scale_y, $scale_z) = @_; - - my ($obj_idx, $object) = $self->selected_object; - - if ((defined $obj_idx) && ($self->{object_info_size})) { # have we already loaded the info pane? - $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", $size_x, $size_y, $size_z)); - my $model_object = $self->{model}->objects->[$obj_idx]; - if (my $stats = $model_object->mesh_stats) { - $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * $scale_x * $scale_y * $scale_z)); - } - } - }; - - # callbacks for toolbar - my $on_action_add = sub { - $self->add; - }; - - my $on_action_delete = sub { - $self->remove(); - }; - - my $on_action_deleteall = sub { - $self->reset; - }; - - my $on_action_arrange = sub { - $self->arrange; - }; - - my $on_action_more = sub { - $self->increase; - }; - - my $on_action_fewer = sub { - $self->decrease; - }; - - my $on_action_split = sub { - $self->split_object; - }; - - my $on_action_cut = sub { - $self->object_cut_dialog; - }; - - my $on_action_settings = sub { - $self->object_settings_dialog; - }; - - my $on_action_layersediting = sub { - my $state = Slic3r::GUI::_3DScene::is_toolbar_item_pressed($self->{canvas3D}, "layersediting"); - $self->on_layer_editing_toggled($state); - }; - - my $on_action_selectbyparts = sub { - my $curr = Slic3r::GUI::_3DScene::get_select_by($self->{canvas3D}); - if ($curr eq 'volume') { - Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object'); - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); - } - elsif ($curr eq 'object') { - Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'volume'); - my $selections = []; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); - - my ($obj_idx, $object) = $self->selected_object; - if (defined $obj_idx) { - my $vol_idx = Slic3r::GUI::_3DScene::get_first_volume_id($self->{canvas3D}, $obj_idx); - #Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx) if ($vol_idx != -1); - my $inst_cnt = $self->{model}->objects->[$obj_idx]->instances_count; - for (0..$inst_cnt-1){ - Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $_ + $vol_idx) if ($vol_idx != -1); - } - - my $volume_idx = Slic3r::GUI::_3DScene::get_in_object_volume_id($self->{canvas3D}, $vol_idx); - Slic3r::GUI::select_current_volume($obj_idx, $volume_idx) if ($volume_idx != -1); - } - } - }; - - # Initialize 3D plater - if ($Slic3r::GUI::have_OpenGL) { - $self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config}); - $self->{preview_notebook}->AddPage($self->{canvas3D}, L('3D')); - Slic3r::GUI::_3DScene::register_on_select_object_callback($self->{canvas3D}, $on_select_object); -# Slic3r::GUI::_3DScene::register_on_double_click_callback($self->{canvas3D}, $on_double_click); - Slic3r::GUI::_3DScene::register_on_right_click_callback($self->{canvas3D}, sub { $on_right_click->($self->{canvas3D}, @_); }); - Slic3r::GUI::_3DScene::register_on_arrange_callback($self->{canvas3D}, sub { $self->arrange }); - Slic3r::GUI::_3DScene::register_on_rotate_object_left_callback($self->{canvas3D}, sub { $self->rotate(-45, Z, 'relative') }); - Slic3r::GUI::_3DScene::register_on_rotate_object_right_callback($self->{canvas3D}, sub { $self->rotate( 45, Z, 'relative') }); - Slic3r::GUI::_3DScene::register_on_scale_object_uniformly_callback($self->{canvas3D}, sub { $self->changescale(undef) }); - Slic3r::GUI::_3DScene::register_on_increase_objects_callback($self->{canvas3D}, sub { $self->increase() }); - Slic3r::GUI::_3DScene::register_on_decrease_objects_callback($self->{canvas3D}, sub { $self->decrease() }); - Slic3r::GUI::_3DScene::register_on_remove_object_callback($self->{canvas3D}, sub { $self->remove() }); - Slic3r::GUI::_3DScene::register_on_instance_moved_callback($self->{canvas3D}, $on_instances_moved); - Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); - Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); - Slic3r::GUI::_3DScene::register_on_gizmo_scale_3D_callback($self->{canvas3D}, $on_gizmo_scale_3D); - Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); - Slic3r::GUI::_3DScene::register_on_gizmo_rotate_3D_callback($self->{canvas3D}, $on_gizmo_rotate_3D); - Slic3r::GUI::_3DScene::register_on_gizmo_flatten_callback($self->{canvas3D}, $on_gizmo_flatten); - Slic3r::GUI::_3DScene::register_on_gizmo_flatten_3D_callback($self->{canvas3D}, $on_gizmo_flatten_3D); - Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); - Slic3r::GUI::_3DScene::register_on_update_geometry_3D_info_callback($self->{canvas3D}, $on_update_geometry_3D_info); - Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add); - Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete); - Slic3r::GUI::_3DScene::register_action_deleteall_callback($self->{canvas3D}, $on_action_deleteall); - Slic3r::GUI::_3DScene::register_action_arrange_callback($self->{canvas3D}, $on_action_arrange); - Slic3r::GUI::_3DScene::register_action_more_callback($self->{canvas3D}, $on_action_more); - Slic3r::GUI::_3DScene::register_action_fewer_callback($self->{canvas3D}, $on_action_fewer); - Slic3r::GUI::_3DScene::register_action_split_callback($self->{canvas3D}, $on_action_split); - Slic3r::GUI::_3DScene::register_action_cut_callback($self->{canvas3D}, $on_action_cut); - Slic3r::GUI::_3DScene::register_action_settings_callback($self->{canvas3D}, $on_action_settings); - Slic3r::GUI::_3DScene::register_action_layersediting_callback($self->{canvas3D}, $on_action_layersediting); - Slic3r::GUI::_3DScene::register_action_selectbyparts_callback($self->{canvas3D}, $on_action_selectbyparts); - Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1); - Slic3r::GUI::_3DScene::enable_toolbar($self->{canvas3D}, 1); - Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1); - Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1); - - Slic3r::GUI::_3DScene::register_on_wipe_tower_moved_callback($self->{canvas3D}, sub { - my ($x, $y) = @_; - my $cfg = Slic3r::Config->new; - $cfg->set('wipe_tower_x', $x); - $cfg->set('wipe_tower_y', $y); - $self->GetFrame->{options_tabs}{print}->load_config($cfg); - }); - - Slic3r::GUI::_3DScene::register_on_model_update_callback($self->{canvas3D}, sub { - if (wxTheApp->{app_config}->get("background_processing")) { - $self->schedule_background_process; - } else { - # Hide the print info box, it is no more valid. - $self->print_info_box_show(0); - } - }); - - Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, - sub { - $self->{preview_iface}->set_viewport_from_scene($self->{canvas3D}); - }); -# Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); }); - } - - Slic3r::GUI::register_on_request_update_callback(sub { $self->schedule_background_process; }); - - # Initialize 3D toolpaths preview - if ($Slic3r::GUI::have_OpenGL) { - $self->{preview_iface} = Slic3r::GUI::create_preview_iface($self->{preview_notebook}, $self->{config}, $self->{print}, $self->{gcode_preview_data}); - $self->{preview_page_idx} = $self->{preview_notebook}->GetPageCount-1; - $self->{preview_iface}->register_on_viewport_changed_callback(sub { $self->{preview_iface}->set_viewport_into_scene($self->{canvas3D}); }); -# $self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config}); -# Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1); -# Slic3r::GUI::_3DScene::enable_dynamic_background($self->{preview3D}->canvas, 1); -# Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{preview3D}->canvas, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); }); -# $self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview')); - $self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1; - } - - EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{preview_notebook}, sub { - my $preview = $self->{preview_notebook}->GetCurrentPage; - my $page_id = $self->{preview_notebook}->GetSelection; - if (($preview != $self->{canvas3D}) && ($page_id != $self->{preview_page_idx})) { -# if (($preview != $self->{preview3D}) && ($preview != $self->{canvas3D})) { - $preview->OnActivate if $preview->can('OnActivate'); - } elsif ($page_id == $self->{preview_page_idx}) { - $self->{preview_iface}->reload_print; - # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) - $self->{preview_iface}->set_canvas_as_dirty; -# } elsif ($preview == $self->{preview3D}) { -# $self->{preview3D}->reload_print; -# # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) -# Slic3r::GUI::_3DScene::set_as_dirty($self->{preview3D}->canvas); - } elsif ($preview == $self->{canvas3D}) { - if (Slic3r::GUI::_3DScene::is_reload_delayed($self->{canvas3D})) { - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); - } - # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) - Slic3r::GUI::_3DScene::set_as_dirty($self->{canvas3D}); - } - }); - -# # toolbar for object manipulation -# if (!&Wx::wxMSW) { -# Wx::ToolTip::Enable(1); -# $self->{htoolbar} = Wx::ToolBar->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxTB_TEXT | wxBORDER_SIMPLE | wxTAB_TRAVERSAL); -# $self->{htoolbar}->AddTool(TB_ADD, L("Add…"), Wx::Bitmap->new(Slic3r::var("brick_add.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_REMOVE, L("Delete"), Wx::Bitmap->new(Slic3r::var("brick_delete.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_RESET, L("Delete All"), Wx::Bitmap->new(Slic3r::var("cross.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_ARRANGE, L("Arrange"), Wx::Bitmap->new(Slic3r::var("bricks.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddSeparator; -# $self->{htoolbar}->AddTool(TB_MORE, L("More"), Wx::Bitmap->new(Slic3r::var("add.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_FEWER, L("Fewer"), Wx::Bitmap->new(Slic3r::var("delete.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddSeparator; -# $self->{htoolbar}->AddTool(TB_45CCW, L("45° ccw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_anticlockwise.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_45CW, L("45° cw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_clockwise.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_SCALE, L("Scale…"), Wx::Bitmap->new(Slic3r::var("arrow_out.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_SPLIT, L("Split"), Wx::Bitmap->new(Slic3r::var("shape_ungroup.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_CUT, L("Cut…"), Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddSeparator; -# $self->{htoolbar}->AddTool(TB_SETTINGS, L("Settings…"), Wx::Bitmap->new(Slic3r::var("cog.png"), wxBITMAP_TYPE_PNG), ''); -# $self->{htoolbar}->AddTool(TB_LAYER_EDITING, L('Layer Editing'), Wx::Bitmap->new(Slic3r::var("variable_layer_height.png"), wxBITMAP_TYPE_PNG), wxNullBitmap, 1, 0, 'Layer Editing'); -# } else { -# my %tbar_buttons = ( -# add => L("Add…"), -# remove => L("Delete"), -# reset => L("Delete All"), -# arrange => L("Arrange"), -# increase => "", -# decrease => "", -# rotate45ccw => "", -# rotate45cw => "", -# changescale => L("Scale…"), -# split => L("Split"), -# cut => L("Cut…"), -# settings => L("Settings…"), -# layer_editing => L("Layer editing"), -# ); -# $self->{btoolbar} = Wx::BoxSizer->new(wxHORIZONTAL); -# for (qw(add remove reset arrange increase decrease rotate45ccw rotate45cw changescale split cut settings)) { -# $self->{"btn_$_"} = Wx::Button->new($self, -1, $tbar_buttons{$_}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); -# $self->{btoolbar}->Add($self->{"btn_$_"}); -# } -# $self->{"btn_layer_editing"} = Wx::ToggleButton->new($self, -1, $tbar_buttons{'layer_editing'}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); -# $self->{btoolbar}->Add($self->{"btn_layer_editing"}); -# } - - ### Panel for right column - $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); -# $self->{right_panel} = Wx::ScrolledWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); -# $self->{right_panel}->SetScrollbars(0, 1, 1, 1); - - ### Scrolled Window for panel without "Export G-code" and "Slice now" buttons - my $scrolled_window_sizer = $self->{scrolled_window_sizer} = Wx::BoxSizer->new(wxVERTICAL); - $scrolled_window_sizer->SetMinSize([320, -1]); - my $scrolled_window_panel = $self->{scrolled_window_panel} = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - $scrolled_window_panel->SetSizer($scrolled_window_sizer); - $scrolled_window_panel->SetScrollbars(0, 1, 1, 1); - - # right pane buttons - $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30],);# wxNO_BORDER);#, wxBU_LEFT); - $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30]);#, wxNO_BORDER);#, wxBU_LEFT); -# $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT); -# $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT); - $self->{btn_print} = Wx::Button->new($scrolled_window_panel, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT); - $self->{btn_send_gcode} = Wx::Button->new($scrolled_window_panel, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT); - #$self->{btn_export_stl} = Wx::Button->new($self->{right_panel}, -1, L("Export STL…"), wxDefaultPosition, [-1, 30], wxBU_LEFT); - #$self->{btn_export_gcode}->SetFont($Slic3r::GUI::small_font); - #$self->{btn_export_stl}->SetFont($Slic3r::GUI::small_font); - $self->{btn_print}->Hide; - $self->{btn_send_gcode}->Hide; - -# export_gcode cog_go.png -#! reslice reslice.png - my %icons = qw( - print arrow_up.png - send_gcode arrow_up.png - export_stl brick_go.png - ); - for (grep $self->{"btn_$_"}, keys %icons) { - $self->{"btn_$_"}->SetBitmap(Wx::Bitmap->new(Slic3r::var($icons{$_}), wxBITMAP_TYPE_PNG)); - } - $self->selection_changed(0); - $self->object_list_changed; - EVT_BUTTON($self, $self->{btn_export_gcode}, sub { - $self->export_gcode; - }); - EVT_BUTTON($self, $self->{btn_print}, sub { - $self->{print_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir()); - }); - EVT_BUTTON($self, $self->{btn_send_gcode}, sub { - $self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir()); - }); - EVT_BUTTON($self, $self->{btn_reslice}, \&reslice); - EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl); - -# if ($self->{htoolbar}) { -# EVT_TOOL($self, TB_ADD, sub { $self->add; }); -# EVT_TOOL($self, TB_REMOVE, sub { $self->remove() }); # explicitly pass no argument to remove -# EVT_TOOL($self, TB_RESET, sub { $self->reset; }); -# EVT_TOOL($self, TB_ARRANGE, sub { $self->arrange; }); -# EVT_TOOL($self, TB_MORE, sub { $self->increase; }); -# EVT_TOOL($self, TB_FEWER, sub { $self->decrease; }); -# EVT_TOOL($self, TB_45CW, sub { $_[0]->rotate(-45, Z, 'relative') }); -# EVT_TOOL($self, TB_45CCW, sub { $_[0]->rotate(45, Z, 'relative') }); -# EVT_TOOL($self, TB_SCALE, sub { $self->changescale(undef); }); -# EVT_TOOL($self, TB_SPLIT, sub { $self->split_object; }); -# EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog }); -# EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog }); -# EVT_TOOL($self, TB_LAYER_EDITING, sub { -# my $state = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D}); -# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state); -# $self->on_layer_editing_toggled(! $state); -# }); -# } else { -# EVT_BUTTON($self, $self->{btn_add}, sub { $self->add; }); -# EVT_BUTTON($self, $self->{btn_remove}, sub { $self->remove() }); # explicitly pass no argument to remove -# EVT_BUTTON($self, $self->{btn_remove}, sub { Slic3r::GUI::remove_obj() }); # explicitly pass no argument to remove -# EVT_BUTTON($self, $self->{btn_reset}, sub { $self->reset; }); -# EVT_BUTTON($self, $self->{btn_arrange}, sub { $self->arrange; }); -# EVT_BUTTON($self, $self->{btn_increase}, sub { $self->increase; }); -# EVT_BUTTON($self, $self->{btn_decrease}, sub { $self->decrease; }); -# EVT_BUTTON($self, $self->{btn_rotate45cw}, sub { $_[0]->rotate(-45, Z, 'relative') }); -# EVT_BUTTON($self, $self->{btn_rotate45ccw}, sub { $_[0]->rotate(45, Z, 'relative') }); -# EVT_BUTTON($self, $self->{btn_changescale}, sub { $self->changescale(undef); }); -# EVT_BUTTON($self, $self->{btn_split}, sub { $self->split_object; }); -# EVT_BUTTON($self, $self->{btn_cut}, sub { $_[0]->object_cut_dialog }); -# EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog }); -# EVT_TOGGLEBUTTON($self, $self->{btn_layer_editing}, sub { $self->on_layer_editing_toggled($self->{btn_layer_editing}->GetValue); }); -# } - - $_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self)) - for grep defined($_), - $self, $self->{canvas3D}, $self->{preview_iface}, $self->{list}; -# $self, $self->{canvas3D}, $self->{preview3D}, $self->{list}; -# $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}; - - EVT_COMMAND($self, -1, $SLICING_COMPLETED_EVENT, sub { - my ($self, $event) = @_; - $self->on_update_print_preview; - }); - - EVT_COMMAND($self, -1, $PROCESS_COMPLETED_EVENT, sub { - my ($self, $event) = @_; - $self->on_process_completed($event->GetInt ? undef : $event->GetString); - }); - -# XXX: not done - { - my $timer_id = Wx::NewId(); - $self->{apply_config_timer} = Wx::Timer->new($self, $timer_id); - EVT_TIMER($self, $timer_id, sub { - my ($self, $event) = @_; - $self->async_apply_config; - }); - } - -# $self->{canvas}->update_bed_size; - if ($self->{canvas3D}) { - Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape); - Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D}); - } - $self->{preview_iface}->set_bed_shape($self->{config}->bed_shape) if ($self->{preview_iface}); -# if ($self->{preview3D}) { -# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape); -# } - $self->update; - - { - my $presets; - { - $presets = $self->{presets_sizer} = Wx::FlexGridSizer->new(4, 2, 1, 2); - $presets->AddGrowableCol(1, 1); - $presets->SetFlexibleDirection(wxHORIZONTAL); - my %group_labels = ( - print => L('Print settings'), - filament => L('Filament'), - sla_material=> L('SLA material'), - printer => L('Printer'), - ); - # UI Combo boxes for a print, multiple filaments, SLA material and a printer. - # Initially a single filament combo box is created, but the number of combo boxes for the filament selection may increase, - # once a printer preset with multiple extruders is activated. - # $self->{preset_choosers}{$group}[$idx] - $self->{preset_choosers} = {}; - for my $group (qw(print filament sla_material printer)) { -# my $text = Wx::StaticText->new($self->{right_panel}, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - $text->SetFont($Slic3r::GUI::small_font); -# my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY); - my $choice = Wx::BitmapComboBox->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY); - if ($group eq 'filament') { - EVT_LEFT_DOWN($choice, sub { $self->filament_color_box_lmouse_down(0, @_); } ); - } - $self->{preset_choosers}{$group} = [$choice]; - # setup the listener - EVT_COMBOBOX($choice, $choice, sub { - my ($choice) = @_; - wxTheApp->CallAfter(sub { - $self->_on_select_preset($group, $choice, 0); - }); - }); - $presets->Add($text, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4); - $presets->Add($choice, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxBOTTOM, 1); - } - $presets->Layout; - } - - my $frequently_changed_parameters_sizer = $self->{frequently_changed_parameters_sizer} = Wx::BoxSizer->new(wxVERTICAL); -#! Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets); - Slic3r::GUI::add_frequently_changed_parameters($self->{scrolled_window_panel}, $frequently_changed_parameters_sizer, $presets); - - my $object_info_sizer; - { - my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Info")); -# my $box = Wx::StaticBox->new($self->{right_panel}, -1, L("Info")); - $box->SetFont($Slic3r::GUI::small_bold_font); - $object_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL); - $object_info_sizer->SetMinSize([300,-1]); - #!my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5); - my $grid_sizer = Wx::FlexGridSizer->new(2, 4, 5, 5); - $grid_sizer->SetFlexibleDirection(wxHORIZONTAL); - $grid_sizer->AddGrowableCol(1, 1); - $grid_sizer->AddGrowableCol(3, 1); - $object_info_sizer->Add($grid_sizer, 0, wxEXPAND); - - my @info = ( - size => L("Size"), - volume => L("Volume"), - facets => L("Facets"), - materials => L("Materials"), - manifold => L("Manifold"), - ); - while (my $field = shift @info) { - my $label = shift @info; - my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); -# my $text = Wx::StaticText->new($self->{right_panel}, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - $text->SetFont($Slic3r::GUI::small_font); - #!$grid_sizer->Add($text, 0); - - $self->{"object_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); -# $self->{"object_info_$field"} = Wx::StaticText->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - $self->{"object_info_$field"}->SetFont($Slic3r::GUI::small_font); - if ($field eq 'manifold') { - $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($scrolled_window_panel, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG)); -# $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self->{right_panel}, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG)); - #$self->{object_info_manifold_warning_icon}->Hide; - $self->{"object_info_manifold_warning_icon_show"} = sub { - if ($self->{object_info_manifold_warning_icon}->IsShown() != $_[0]) { - # this fuction show/hide info_manifold_warning_icon on the c++ side now - Slic3r::GUI::set_show_manifold_warning_icon($_[0]); - #my $mode = wxTheApp->{app_config}->get("view_mode"); - #return if ($mode eq "" || $mode eq "simple"); - #$self->{object_info_manifold_warning_icon}->Show($_[0]); - #$self->Layout - } - }; - $self->{"object_info_manifold_warning_icon_show"}->(0); - - my $h_sizer = Wx::BoxSizer->new(wxHORIZONTAL); - $h_sizer->Add($text, 0); - $h_sizer->Add($self->{object_info_manifold_warning_icon}, 0, wxLEFT, 2); - $h_sizer->Add($self->{"object_info_$field"}, 0, wxLEFT, 2); - #!$grid_sizer->Add($h_sizer, 0, wxEXPAND); - $object_info_sizer->Add($h_sizer, 0, wxEXPAND|wxTOP, 4); - } else { - $grid_sizer->Add($text, 0); - $grid_sizer->Add($self->{"object_info_$field"}, 0); - } - } - } - - my $print_info_box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info")); - $print_info_box->SetFont($Slic3r::GUI::small_bold_font); - my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new($print_info_box, wxVERTICAL); -# Wx::StaticBox->new($self->{right_panel}, -1, L("Sliced Info")), wxVERTICAL); - $print_info_sizer->SetMinSize([300,-1]); - - my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL); - $self->{buttons_sizer} = $buttons_sizer; - $buttons_sizer->AddStretchSpacer(1); -# $buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0); -#! $buttons_sizer->Add($self->{btn_reslice}, 0, wxALIGN_RIGHT, 0); - $buttons_sizer->Add($self->{btn_print}, 0, wxALIGN_RIGHT | wxBOTTOM | wxTOP, 5); - $buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT | wxBOTTOM | wxTOP, 5); - -# $scrolled_window_sizer->Add($self->{list}, 1, wxEXPAND, 5); -# $scrolled_window_sizer->Add($object_info_sizer, 0, wxEXPAND, 0); -# $scrolled_window_sizer->Add($print_info_sizer, 0, wxEXPAND, 0); - #$buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0); - - ### Sizer for info boxes - my $info_sizer = $self->{info_sizer} = Wx::BoxSizer->new(wxVERTICAL); - $info_sizer->SetMinSize([318, -1]); - $info_sizer->Add($object_info_sizer, 0, wxEXPAND | wxTOP, 20); - $info_sizer->Add($print_info_sizer, 0, wxEXPAND | wxTOP, 20); - - $scrolled_window_sizer->Add($presets, 0, wxEXPAND | wxLEFT, 2) if defined $presets; - $scrolled_window_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxLEFT, 0) if defined $frequently_changed_parameters_sizer; - $scrolled_window_sizer->Add($buttons_sizer, 0, wxEXPAND, 0); - $scrolled_window_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20); - # Show the box initially, let it be shown after the slicing is finished. - $self->print_info_box_show(0); - - ### Sizer for "Export G-code" & "Slice now" buttons - my $btns_sizer = Wx::BoxSizer->new(wxVERTICAL); - $btns_sizer->SetMinSize([318, -1]); - $btns_sizer->Add($self->{btn_reslice}, 0, wxEXPAND, 0); - $btns_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxTOP, 5); - - my $right_sizer = Wx::BoxSizer->new(wxVERTICAL); - $self->{right_panel}->SetSizer($right_sizer); - $right_sizer->SetMinSize([320, -1]); -#! $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets; -#! $right_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer; -#! $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, 10); -#! $right_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20); - # Show the box initially, let it be shown after the slicing is finished. -#! $self->print_info_box_show(0); - $right_sizer->Add($scrolled_window_panel, 1, wxEXPAND | wxTOP, 5); -# $right_sizer->Add($self->{btn_reslice}, 0, wxEXPAND | wxLEFT | wxTOP, 20); -# $right_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxLEFT | wxTOP, 20); - $right_sizer->Add($btns_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 20); - - my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); - $hsizer->Add($self->{preview_notebook}, 1, wxEXPAND | wxTOP, 1); - $hsizer->Add($self->{right_panel}, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);#3); - - my $sizer = Wx::BoxSizer->new(wxVERTICAL); -# $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar}; -# $sizer->Add($self->{btoolbar}, 0, wxEXPAND, 0) if $self->{btoolbar}; - $sizer->Add($hsizer, 1, wxEXPAND, 0); - - $sizer->SetSizeHints($self); - $self->SetSizer($sizer); - - # Send sizers/buttons to C++ - Slic3r::GUI::set_objects_from_perl( $self->{scrolled_window_panel}, - $frequently_changed_parameters_sizer, - $info_sizer, - $self->{btn_export_gcode}, - # $self->{btn_export_stl}, - $self->{btn_reslice}, - $self->{btn_print}, - $self->{btn_send_gcode}, - $self->{object_info_manifold_warning_icon} ); - - Slic3r::GUI::set_model_events_from_perl( $self->{model}, - $self->{event_object_selection_changed}, - $self->{event_object_settings_changed}, - $self->{event_remove_object}, - $self->{event_update_scene}); - } - - # Last correct selected item for each preset - { - $self->{selected_item_print} = 0; - $self->{selected_item_filament} = 0; - $self->{selected_item_printer} = 0; - } - - $self->update_ui_from_settings(); - $self->Layout; - - return $self; -} - -# XXX: VK: WIP -# sets the callback -sub on_select_preset { - my ($self, $cb) = @_; - $self->{on_select_preset} = $cb; -} - -# XXX: merged with on_select_preset -# Called from the platter combo boxes selecting the active print, filament or printer. -sub _on_select_preset { - my ($self, $group, $choice, $idx) = @_; - # If user changed a filament preset and the selected machine is equipped with multiple extruders, - # there are multiple filament selection combo boxes shown at the platter. In that case - # don't propagate the filament selection changes to the tab. - if ($group eq 'filament') { - wxTheApp->{preset_bundle}->set_filament_preset($idx, $choice->GetStringSelection); - } - if ($group eq 'filament' && @{$self->{preset_choosers}{filament}} > 1) { - # Only update the platter UI for the 2nd and other filaments. - wxTheApp->{preset_bundle}->update_platter_filament_ui($idx, $choice); - } else { - my $selected_item = $choice->GetSelection(); - return if ($selected_item == $self->{"selected_item_$group"} && - !Slic3r::GUI::get_preset_tab($group)->current_preset_is_dirty); - - my $selected_string = $choice->GetString($selected_item); - if ($selected_string eq ("------- ".L("System presets")." -------") || - $selected_string eq ("------- ".L("User presets")." -------") ){ - $choice->SetSelection($self->{"selected_item_$group"}); - return; - } - - # call GetSelection() in scalar context as it's context-aware -# $self->{on_select_preset}->($group, $choice->GetStringSelection) - $self->{on_select_preset}->($group, $selected_string) - if $self->{on_select_preset}; - $self->{"selected_item_$group"} = $selected_item; - } - # Synchronize config.ini with the current selections. - wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config}); - # get new config and generate on_config_change() event for updating plater and other things - $self->on_config_change(wxTheApp->{preset_bundle}->full_config); -} - -# XXX: VK: done -sub on_layer_editing_toggled { - my ($self, $new_state) = @_; - Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, $new_state); - if ($new_state && ! Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D})) { - # Initialization of the OpenGL shaders failed. Disable the tool. -# if ($self->{htoolbar}) { -# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0); -# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0); -# } else { -# $self->{"btn_layer_editing"}->Disable; -# $self->{"btn_layer_editing"}->SetValue(0); -# } - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 0); - } - $self->{canvas3D}->Refresh; - $self->{canvas3D}->Update; -} - -# XXX: VK: done (Plater::priv::main_frame) -sub GetFrame { - my ($self) = @_; - return &Wx::GetTopLevelParent($self); -} - -# XXX: not done -# Called after the Preferences dialog is closed and the program settings are saved. -# Update the UI based on the current preferences. -sub update_ui_from_settings -{ - my ($self) = @_; - if (defined($self->{btn_reslice}) && $self->{buttons_sizer}->IsShown($self->{btn_reslice}) != (! wxTheApp->{app_config}->get("background_processing"))) { - $self->{buttons_sizer}->Show($self->{btn_reslice}, ! wxTheApp->{app_config}->get("background_processing")); - $self->{buttons_sizer}->Layout; - } -} - -# XXX: VK: done -# Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs. -# Called by -# Slic3r::GUI::Tab::Print::_on_presets_changed -# Slic3r::GUI::Tab::Filament::_on_presets_changed -# Slic3r::GUI::Tab::Material::_on_presets_changed -# Slic3r::GUI::Tab::Printer::_on_presets_changed -# when the presets are loaded or the user selects another preset. -# For Print settings and Printer, synchronize the selection index with their tabs. -# For Filament, synchronize the selection index for a single extruder printer only, otherwise keep the selection. -sub update_presets { - # $group: one of qw(print filament sla_material printer) - # $presets: PresetCollection - my ($self, $group, $presets) = @_; - my @choosers = @{$self->{preset_choosers}{$group}}; - if ($group eq 'filament') { - my $choice_idx = 0; - if (int(@choosers) == 1) { - # Single filament printer, synchronize the filament presets. - wxTheApp->{preset_bundle}->set_filament_preset(0, wxTheApp->{preset_bundle}->filament->get_selected_preset->name); - } - foreach my $choice (@choosers) { - wxTheApp->{preset_bundle}->update_platter_filament_ui($choice_idx, $choice); - $choice_idx += 1; - } - } elsif ($group eq 'print') { - wxTheApp->{preset_bundle}->print->update_platter_ui($choosers[0]); - } elsif ($group eq 'sla_material') { - wxTheApp->{preset_bundle}->sla_material->update_platter_ui($choosers[0]); - } elsif ($group eq 'printer') { - # Update the print choosers to only contain the compatible presets, update the dirty flags. - wxTheApp->{preset_bundle}->print->update_platter_ui($self->{preset_choosers}{print}->[0]); - # Update the printer choosers, update the dirty flags. - wxTheApp->{preset_bundle}->printer->update_platter_ui($choosers[0]); - # Update the filament choosers to only contain the compatible presets, update the color preview, - # update the dirty flags. - my $choice_idx = 0; - foreach my $choice (@{$self->{preset_choosers}{filament}}) { - wxTheApp->{preset_bundle}->update_platter_filament_ui($choice_idx, $choice); - $choice_idx += 1; - } - } - # Synchronize config.ini with the current selections. - wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config}); -} - -# XXX: VK: done, in on_action_add() -sub add { - my ($self) = @_; - my @input_files = wxTheApp->open_model($self); - $self->load_files(\@input_files); -} - -# XXX: VK: done -sub load_files { - my ($self, $input_files) = @_; - - return if ! defined($input_files) || ! scalar(@$input_files); - - my $nozzle_dmrs = $self->{config}->get('nozzle_diameter'); - # One of the files is potentionally a bundle of files. Don't bundle them, but load them one by one. - # Only bundle .stls or .objs if the printer has multiple extruders. - my $one_by_one = (@$nozzle_dmrs <= 1) || (@$input_files == 1) || - defined(first { $_ =~ /.[aA][mM][fF]$/ || $_ =~ /.[aA][mM][fF].[xX][mM][lL]$/ || $_ =~ /.[zZ][iI][pP].[aA][mM][fF]$/ || $_ =~ /.3[mM][fF]$/ || $_ =~ /.[pP][rR][uI][sS][aA]$/ } @$input_files); - - my $process_dialog = Wx::ProgressDialog->new(L('Loading…'), L("Processing input file\n") . basename($input_files->[0]), 100, $self, 0); - $process_dialog->Pulse; - local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); - - # new_model to collect volumes, if all of them come from .stl or .obj and there is a chance, that they will be - # possibly merged into a single multi-part object. - my $new_model = $one_by_one ? undef : Slic3r::Model->new; - # Object indices for the UI. - my @obj_idx = (); - # Collected file names to display the final message on the status bar. - my @loaded_files = (); # XXX: used??? - # For all input files. - for (my $i = 0; $i < @$input_files; $i += 1) { - my $input_file = $input_files->[$i]; - $process_dialog->Update(100. * $i / @$input_files, L("Processing input file\n") . basename($input_file)); - - my $model; - if (($input_file =~ /.3[mM][fF]$/) || ($input_file =~ /.[zZ][iI][pP].[aA][mM][fF]$/)) - { - $model = eval { Slic3r::Model->read_from_archive($input_file, wxTheApp->{preset_bundle}, 0) }; - Slic3r::GUI::show_error($self, $@) if $@; - $_->load_current_preset for (values %{$self->GetFrame->{options_tabs}}); - wxTheApp->{app_config}->update_config_dir(dirname($input_file)); - # forces the update of the config here, or it will invalidate the imported layer heights profile if done using the timer - # and if the config contains a "layer_height" different from the current defined one - $self->async_apply_config; - } - else - { - $model = eval { Slic3r::Model->read_from_file($input_file, 0) }; - Slic3r::GUI::show_error($self, $@) if $@; - } - - next if ! defined $model; - - if ($model->looks_like_multipart_object) { - my $dialog = Wx::MessageDialog->new($self, - L("This file contains several objects positioned at multiple heights. " - . "Instead of considering them as multiple objects, should I consider\n" - . "this file as a single object having multiple parts?\n"), - L('Multi-part object detected'), wxICON_WARNING | wxYES | wxNO); - $model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES; - } - - # objects imported from 3mf require a call to center_around_origin to have gizmos working properly and this call - # need to be done after looks_like_multipart_object detection - if ($input_file =~ /[.]3[mM][fF]$/) - { - foreach my $model_object (@{$model->objects}) { - $model_object->center_around_origin; # also aligns object to Z = 0 - } - } - - if ($one_by_one) { - push @obj_idx, $self->load_model_objects(@{$model->objects}); - } else { - # This must be an .stl or .obj file, which may contain a maximum of one volume. - $new_model->add_object($_) for (@{$model->objects}); - } - } - - if ($new_model) { - my $dialog = Wx::MessageDialog->new($self, - L("Multiple objects were loaded for a multi-material printer.\n" - . "Instead of considering them as multiple objects, should I consider\n" - . "these files to represent a single object having multiple parts?\n"), - L('Multi-part object detected'), wxICON_WARNING | wxYES | wxNO); - $new_model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES; - push @obj_idx, $self->load_model_objects(@{$new_model->objects}); - } - - # Note the current directory for the file open dialog. - wxTheApp->{app_config}->update_skein_dir(dirname($input_files->[-1])); - - $process_dialog->Destroy; - $self->statusbar->SetStatusText(L("Loaded ") . join(',', @loaded_files)); - return @obj_idx; -} - -# XXX: VK: done, except a few todos -sub load_model_objects { - my ($self, @model_objects) = @_; - - my $bed_centerf = $self->bed_centerf; - my $bed_shape = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape}); - my $bed_size = $bed_shape->bounding_box->size; - - my $need_arrange = 0; - my $scaled_down = 0; - my @obj_idx = (); - foreach my $model_object (@model_objects) { - my $o = $self->{model}->add_object($model_object); - my $object_name = $model_object->name; - $object_name = basename($model_object->input_file) if ($object_name eq ''); - push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(name => $object_name); - push @obj_idx, $#{ $self->{objects} }; - - if ($model_object->instances_count == 0) { - # if object has no defined position(s) we need to rearrange everything after loading - $need_arrange = 1; - - # add a default instance and center object around origin - $o->center_around_origin; # also aligns object to Z = 0 - $o->add_instance(offset => $bed_centerf); - } - - { - # if the object is too large (more than 5 times the bed), scale it down - my $size = $o->bounding_box->size; - my $ratio = max($size->x / unscale($bed_size->x), $size->y / unscale($bed_size->y)); - if ($ratio > 10000) { - # the size of the object is too big -> this could lead to overflow when moving to clipper coordinates, - # so scale down the mesh - $o->scale_xyz(Slic3r::Pointf3->new(1/$ratio, 1/$ratio, 1/$ratio)); - $scaled_down = 1; - } - elsif ($ratio > 5) { - $_->set_scaling_factor(1/$ratio) for @{$o->instances}; - $scaled_down = 1; - } - } - - $self->{print}->auto_assign_extruders($o); - $self->{print}->add_model_object($o); - } - - # if user turned autocentering off, automatic arranging would disappoint them - if (! wxTheApp->{app_config}->get("autocenter")) { - $need_arrange = 0; - } - - if ($scaled_down) { - Slic3r::GUI::show_info( - $self, - L('Your object appears to be too large, so it was automatically scaled down to fit your print bed.'), - L('Object too large?'), - ); - } - - foreach my $obj_idx (@obj_idx) { - my $object = $self->{objects}[$obj_idx]; - my $model_object = $self->{model}->objects->[$obj_idx]; - - # Add object to list on c++ side - Slic3r::GUI::add_object_to_list($object->name, $model_object); - - -# $self->reset_thumbnail($obj_idx); - } - $self->arrange if $need_arrange; - $self->update; - - # zoom to objects - Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D}; - - $self->object_list_changed; - - $self->schedule_background_process; - - return @obj_idx; -} - -# XXX: Removed, replaced with bed_shape_bb() -sub bed_centerf { - my ($self) = @_; - - my $bed_shape = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape}); - my $bed_center = $bed_shape->bounding_box->center; - return Slic3r::Pointf->new(unscale($bed_center->x), unscale($bed_center->y)); #) -} - -# XXX: VK: done -sub remove { - my ($self, $obj_idx) = @_; - - $self->stop_background_process; - - # Prevent toolpaths preview from rendering while we modify the Print object - $self->{preview_iface}->set_enabled(0) if $self->{preview_iface}; -# $self->{preview3D}->enabled(0) if $self->{preview3D}; - - # If no object index is supplied, remove the selected one. - if (! defined $obj_idx) { - ($obj_idx, undef) = $self->selected_object; - return if ! defined $obj_idx; - } - - splice @{$self->{objects}}, $obj_idx, 1; - $self->{model}->delete_object($obj_idx); - $self->{print}->delete_object($obj_idx); - # Delete object from list on c++ side - Slic3r::GUI::delete_object_from_list(); - $self->object_list_changed; - - $self->select_object(undef); - $self->update; -} - -# XXX: VK: done -sub reset { - my ($self) = @_; - - $self->stop_background_process; - - # Prevent toolpaths preview from rendering while we modify the Print object - $self->{preview_iface}->set_enabled(0) if $self->{preview_iface}; -# $self->{preview3D}->enabled(0) if $self->{preview3D}; - - @{$self->{objects}} = (); - $self->{model}->clear_objects; - $self->{print}->clear_objects; - # Delete all objects from list on c++ side - Slic3r::GUI::delete_all_objects_from_list(); - $self->object_list_changed; - - $self->select_object(undef); - $self->update; -} - -# XXX: VK: done -sub increase { - my ($self, $copies) = @_; - $copies //= 1; - my ($obj_idx, $object) = $self->selected_object; - return if ! defined $obj_idx; - my $model_object = $self->{model}->objects->[$obj_idx]; - my $instance = $model_object->instances->[-1]; - $self->stop_background_process; - for my $i (1..$copies) { - $instance = $model_object->add_instance( - offset => Slic3r::Pointf->new(map 10+$_, @{$instance->offset}), - scaling_factor => $instance->scaling_factor, - rotation => $instance->rotation, - ); - $self->{print}->objects->[$obj_idx]->add_copy($instance->offset); - } - # Set count of object on c++ side - Slic3r::GUI::set_object_count($obj_idx, $model_object->instances_count); - - # only autoarrange if user has autocentering enabled - $self->stop_background_process; - if (wxTheApp->{app_config}->get("autocenter")) { - $self->arrange; - } else { - $self->update; - } - - $self->selection_changed; # refresh info (size, volume etc.) - $self->schedule_background_process; -} - -# XXX: VK: done -sub decrease { - my ($self, $copies_asked) = @_; - my $copies = $copies_asked // 1; - my ($obj_idx, $object) = $self->selected_object; - return if ! defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - if ($model_object->instances_count > $copies) { - $self->stop_background_process; - for my $i (1..$copies) { - $model_object->delete_last_instance; - $self->{print}->objects->[$obj_idx]->delete_last_copy; - } - # Set conut of object on c++ side - Slic3r::GUI::set_object_count($obj_idx, $model_object->instances_count); - } elsif (defined $copies_asked) { - # The "decrease" came from the "set number of copies" dialog. - $self->stop_background_process; - $self->remove; - } else { - # The "decrease" came from the "-" button. Don't allow the object to disappear. - return; - } - - $self->update; -} - -# XXX: VK: done -sub set_number_of_copies { - my ($self) = @_; - # get current number of copies - my ($obj_idx, $object) = $self->selected_object; - my $model_object = $self->{model}->objects->[$obj_idx]; - # prompt user - my $copies = -1; - $copies = Wx::GetNumberFromUser("", L("Enter the number of copies of the selected object:"), L("Copies"), $model_object->instances_count, 0, 1000, $self); - my $diff = $copies - $model_object->instances_count; - if ($diff == 0 || $copies == -1) { - # no variation - } elsif ($diff > 0) { - $self->increase($diff); - } elsif ($diff < 0) { - $self->decrease(-$diff); - } -} - -# XXX: VK: removed -sub _get_number_from_user { - my ($self, $title, $prompt_message, $error_message, $default, $only_positive) = @_; - for (;;) { - my $value = Wx::GetTextFromUser($prompt_message, $title, $default, $self); - # Accept both dashes and dots as a decimal separator. - $value =~ s/,/./; - # If scaling value is being entered, remove the trailing percent sign. - $value =~ s/%$// if $only_positive; - # User canceled the selection, return undef. - return if $value eq ''; - # Validate a numeric value. - return $value if ($value =~ /^-?\d*(?:\.\d*)?$/) && (! $only_positive || $value > 0); - Wx::MessageBox( - $error_message . - (($only_positive && $value <= 0) ? - ": ".$value.L("\nNon-positive value.") : - ": ".$value.L("\nNot a numeric value.")), - L("Slic3r Error"), wxOK | wxICON_EXCLAMATION, $self); - $default = $value; - } -} - -# XXX: not done -sub rotate { - my ($self, $angle, $axis, $relative_key, $axis_x, $axis_y, $axis_z) = @_; - $relative_key //= 'absolute'; # relative or absolute coordinates - $axis_x //= 0; - $axis_y //= 0; - $axis_z //= 0; - my $relative = $relative_key eq 'relative'; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - if (!defined $angle) { - my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z'; - my $default = $axis == Z ? rad2deg($model_instance->rotation) : 0; - $angle = $self->_get_number_from_user(L("Enter the rotation angle:"), L("Rotate around ").$axis_name.(" axis"), L("Invalid rotation angle entered"), $default); - return if $angle eq ''; - } - - # Let's calculate vector of rotation axis (if we don't have it already) - if (defined $axis) { - if ($axis == X) { - $axis_x = 1; - } - if ($axis == Y) { - $axis_y = 1; - } - } - - $self->stop_background_process; - - if (defined $axis && $axis == Z) { - my $new_angle = deg2rad($angle); - foreach my $inst (@{ $model_object->instances }) { - my $rotation = ($relative ? $inst->rotation : 0.) + $new_angle; - while ($rotation > 2.0 * PI) { - $rotation -= 2.0 * PI; - } - while ($rotation < 0.0) { - $rotation += 2.0 * PI; - } - $inst->set_rotation($rotation); - Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); - } -# $object->transform_thumbnail($self->{model}, $obj_idx); - } else { - if (defined $axis) { - # rotation around X and Y needs to be performed on mesh - # so we first apply any Z rotation - if ($model_instance->rotation != 0) { - $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, -1)); - $_->set_rotation(0) for @{ $model_object->instances }; - } - } - $model_object->rotate(deg2rad($angle), Slic3r::Pointf3->new($axis_x, $axis_y, $axis_z)); - -# # realign object to Z = 0 -# $model_object->center_around_origin; -# $self->reset_thumbnail($obj_idx); - } - - # update print and start background processing - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed; # refresh info (size etc.) - $self->update; -} - -# XXX: not done -sub mirror { - my ($self, $axis) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - # apply Z rotation before mirroring - if ($model_instance->rotation != 0) { - $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1)); - $_->set_rotation(0) for @{ $model_object->instances }; - } - - $model_object->mirror($axis); - -# # realign object to Z = 0 -# $model_object->center_around_origin; -# $self->reset_thumbnail($obj_idx); - - # update print and start background processing - $self->stop_background_process; - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed; # refresh info (size etc.) - $self->update; -} - -# XXX: not done, renamed as Plater::priv::scale() -sub changescale { - my ($self, $axis, $tosize) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - my $object_size = $model_object->instance_bounding_box(0)->size; - - if (defined $axis) { - my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z'; - my $scale; - if ($tosize) { - my $cursize = $object_size->[$axis]; - my $newsize = $self->_get_number_from_user( - L('Enter the new size for the selected object:'), - L("Scale along ").$axis_name, L('Invalid scaling value entered'), $cursize, 1); - return if $newsize eq ''; - $scale = $newsize / $cursize * 100; - } else { - $scale = $self->_get_number_from_user(L('Enter the scale % for the selected object:'), L("Scale along ").$axis_name, L('Invalid scaling value entered'), 100, 1); - return if $scale eq ''; - } - - # apply Z rotation before scaling - if ($model_instance->rotation != 0) { - $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1)); - $_->set_rotation(0) for @{ $model_object->instances }; - } - - my $versor = [1,1,1]; - $versor->[$axis] = $scale/100; - $model_object->scale_xyz(Slic3r::Pointf3->new(@$versor)); - #FIXME Scale the layer height profile when $axis == Z? - #FIXME Scale the layer height ranges $axis == Z? - # object was already aligned to Z = 0, so no need to realign it -# $self->reset_thumbnail($obj_idx); - } else { - my $scale; - if ($tosize) { - my $cursize = max(@$object_size); - my $newsize = $self->_get_number_from_user(L('Enter the new max size for the selected object:'), L('Scale'), L('Invalid scaling value entered'), $cursize, 1); - return if ! defined($newsize) || $newsize eq ''; - $scale = $model_instance->scaling_factor * $newsize / $cursize * 100; - } else { - # max scale factor should be above 2540 to allow importing files exported in inches - $scale = $self->_get_number_from_user(L('Enter the scale % for the selected object:'), L('Scale'), L('Invalid scaling value entered'), $model_instance->scaling_factor*100, 1); - return if ! defined($scale) || $scale eq ''; - } - - # Set object scale on c++ side -# Slic3r::GUI::set_object_scale($obj_idx, $scale); - $scale /= 100; # turn percent into factor - - my $variation = $scale / $model_instance->scaling_factor; - #FIXME Scale the layer height profile? - foreach my $range (@{ $model_object->layer_height_ranges }) { - $range->[0] *= $variation; - $range->[1] *= $variation; - } - $_->set_scaling_factor($scale) for @{ $model_object->instances }; -# $object->transform_thumbnail($self->{model}, $obj_idx); - } - - # update print and start background processing - $self->stop_background_process; - $self->{print}->add_model_object($model_object, $obj_idx); - - $self->selection_changed(1); # refresh info (size, volume etc.) - $self->update; -} - -# XXX: VK: WIP -sub arrange { - my ($self) = @_; - - $self->stop_background_process; - # my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape); - # my $success = $self->{model}->arrange_objects(wxTheApp->{preset_bundle}->full_config->min_object_distance, $bb); - - # Update is not implemented in C++ so we cannot call this for now - $self->{appController}->arrange_model; - - # ignore arrange failures on purpose: user has visual feedback and we don't need to warn him - # when parts don't fit in print bed - - # Force auto center of the aligned grid of of objects on the print bed. - $self->update(0); -} - -# XXX: not done -sub split_object { - my $self = shift; - - my ($obj_idx, $current_object) = $self->selected_object; - - # we clone model object because split_object() adds the split volumes - # into the same model object, thus causing duplicates when we call load_model_objects() - my $new_model = $self->{model}->clone; # store this before calling get_object() - my $current_model_object = $new_model->get_object($obj_idx); - - if ($current_model_object->volumes_count > 1) { - Slic3r::GUI::warning_catcher($self)->(L("The selected object can't be split because it contains more than one volume/material.")); - return; - } - - $self->stop_background_process; - - my @model_objects = @{$current_model_object->split_object}; - if (@model_objects == 1) { - Slic3r::GUI::warning_catcher($self)->(L("The selected object couldn't be split because it contains only one part.")); - $self->schedule_background_process; - } else { - $_->center_around_origin for (@model_objects); - $self->remove($obj_idx); - $current_object = $obj_idx = undef; - # load all model objects at once, otherwise the plate would be rearranged after each one - # causing original positions not to be kept - $self->load_model_objects(@model_objects); - } -} - -# XXX: not done -# Trigger $self->async_apply_config() after 500ms. -# The call is delayed to avoid restarting the background processing during typing into an edit field. -sub schedule_background_process { - my ($self) = @_; - $self->{apply_config_timer}->Start(0.5 * 1000, 1); # 1 = one shot, every half a second. -} - -# XXX: not done -# Executed asynchronously by a timer every PROCESS_DELAY (0.5 second). -# The timer is started by schedule_background_process(), -sub async_apply_config { - my ($self) = @_; - # Apply new config to the possibly running background task. - my $was_running = $self->{background_slicing_process}->running; - my $invalidated = $self->{background_slicing_process}->apply_config(wxTheApp->{preset_bundle}->full_config); - # Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. - $self->{canvas3D}->Refresh if Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D}); - # If the apply_config caused the calculation to stop, or it was not running yet: - if ($invalidated) { - if ($was_running) { - # Hide the slicing results if the current slicing status is no more valid. - $self->print_info_box_show(0) - } - if (wxTheApp->{app_config}->get("background_processing")) { - $self->{background_slicing_process}->start; - } - if ($was_running) { - # Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. - # Otherwise they will be just refreshed. - $self->{gcode_preview_data}->reset; - $self->{preview_iface}->reload_print if $self->{preview_iface}; -# $self->{preview3D}->reload_print if $self->{preview3D}; - # We also need to reload 3D scene because of the wipe tower preview box - if ($self->{config}->wipe_tower) { - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1) if $self->{canvas3D} - } - } - } -} - -# XXX: not done -# Background processing is started either by the "Slice now" button, by the "Export G-code button" or by async_apply_config(). -sub start_background_process { - my ($self) = @_; - return if ! @{$self->{objects}} || $self->{background_slicing_process}->running; - # Don't start process thread if config is not valid. - eval { - # this will throw errors if config is not valid - wxTheApp->{preset_bundle}->full_config->validate; - $self->{print}->validate; - }; - if ($@) { - $self->statusbar->SetStatusText($@); - return; - } - # Copy the names of active presets into the placeholder parser. - wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser); - # Start the background process. - $self->{background_slicing_process}->start; -} - -# XXX: not done -# Stop the background processing -sub stop_background_process { - my ($self) = @_; - $self->{background_slicing_process}->stop(); - $self->{preview_iface}->reload_print if $self->{preview_iface}; -# $self->{preview3D}->reload_print if $self->{preview3D}; -} - -# XXX: not done -# Called by the "Slice now" button, which is visible only if the background processing is disabled. -sub reslice { - # explicitly cancel a previous thread and start a new one. - my ($self) = @_; - # Don't reslice if export of G-code or sending to OctoPrint is running. - if (! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) { - # Stop the background processing threads, stop the async update timer. - $self->stop_background_process; - # Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. - $self->async_apply_config; - $self->statusbar->SetCancelCallback(sub { - $self->stop_background_process; - $self->statusbar->SetStatusText(L("Slicing cancelled")); - # this updates buttons status - $self->object_list_changed; - }); - $self->start_background_process; - } -} - -# XXX: VK: done -sub export_gcode { - my ($self, $output_file) = @_; - - return if !@{$self->{objects}}; - - if ($self->{export_gcode_output_file}) { - Wx::MessageDialog->new($self, L("Another export job is currently running."), L('Error'), wxOK | wxICON_ERROR)->ShowModal; - return; - } - - # if process is not running, validate config - # (we assume that if it is running, config is valid) - eval { - # this will throw errors if config is not valid - wxTheApp->{preset_bundle}->full_config->validate; - $self->{print}->validate; - }; - Slic3r::GUI::catch_error($self) and return; - - - # apply config and validate print - my $config = wxTheApp->{preset_bundle}->full_config; - eval { - # this will throw errors if config is not valid - $config->validate; - #FIXME it shall use the background processing! - $self->{print}->apply_config($config); - $self->{print}->validate; - }; - Slic3r::GUI::catch_error($self) and return; - - # Copy the names of active presets into the placeholder parser. - wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser); - # select output file - if ($output_file) { - $self->{export_gcode_output_file} = eval { $self->{print}->output_filepath($output_file) }; - Slic3r::GUI::catch_error($self) and return; - } else { - my $default_output_file = eval { $self->{print}->output_filepath($main::opt{output} // '') }; - Slic3r::GUI::catch_error($self) and return; - # If possible, remove accents from accented latin characters. - # This function is useful for generating file names to be processed by legacy firmwares. - $default_output_file = Slic3r::GUI::fold_utf8_to_ascii($default_output_file); - my $dlg = Wx::FileDialog->new($self, L('Save G-code file as:'), - wxTheApp->{app_config}->get_last_output_dir(dirname($default_output_file)), - basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if ($dlg->ShowModal != wxID_OK) { - $dlg->Destroy; - return; - } - my $path = $dlg->GetPath; - wxTheApp->{app_config}->update_last_output_dir(dirname($path)); - $self->{export_gcode_output_file} = $path; - $dlg->Destroy; - } - - $self->statusbar->StartBusy; - - $self->statusbar->SetCancelCallback(sub { - $self->stop_background_process; - $self->statusbar->SetStatusText(L("Export cancelled")); - $self->{export_gcode_output_file} = undef; - $self->{send_gcode_file} = undef; - - # this updates buttons status - $self->object_list_changed; - }); - - $self->{background_slicing_process}->set_output_path($self->{export_gcode_output_file}); - - # start background process, whose completion event handler - # will detect $self->{export_gcode_output_file} and proceed with export - $self->start_background_process; - - # this updates buttons status - $self->object_list_changed; - - return $self->{export_gcode_output_file}; -} - -# XXX: not done -# This message should be called by the background process synchronously. -sub on_update_print_preview { - my ($self) = @_; - $self->{preview_iface}->reload_print if $self->{preview_iface}; -# $self->{preview3D}->reload_print if $self->{preview3D}; - - # in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); -} - -# XXX: not done -# This gets called also if we have no threads. -sub on_progress_event { - my ($self, $percent, $message) = @_; - - $self->statusbar->SetProgress($percent); - # TODO: three dot character is not properly translated into C++ - # $self->statusbar->SetStatusText("$message…"); - $self->statusbar->SetStatusText("$message..."); -} - -# XXX: not done -# Called when the G-code export finishes, either successfully or with an error. -# This gets called also if we don't have threads. -sub on_process_completed { - my ($self, $result) = @_; - - # Stop the background task, wait until the thread goes into the "Idle" state. - # At this point of time the thread should be either finished or canceled, - # so the following call just confirms, that the produced data were consumed. - $self->{background_slicing_process}->stop; - $self->statusbar->ResetCancelCallback(); - $self->statusbar->StopBusy; - $self->statusbar->SetStatusText(""); - - my $message; - my $send_gcode = 0; - my $do_print = 0; -# print "Process completed, message: ", $message, "\n"; - if (defined($result)) { - $message = L("Export failed"); - } else { - # G-code file exported successfully. - if ($self->{print_file}) { - $message = L("File added to print queue"); - $do_print = 1; - } elsif ($self->{send_gcode_file}) { - $message = L("Sending G-code file to the Printer Host ..."); - $send_gcode = 1; - } elsif (defined $self->{export_gcode_output_file}) { - $message = L("G-code file exported to ") . $self->{export_gcode_output_file}; - } else { - $message = L("Slicing complete"); - } - } - $self->{export_gcode_output_file} = undef; - wxTheApp->notify($message); - - $self->do_print if $do_print; - - # Send $self->{send_gcode_file} to OctoPrint. - if ($send_gcode) { - my $host = Slic3r::PrintHost::get_print_host($self->{config}); - if ($host->send_gcode($self->{send_gcode_file})) { - $message = L("Upload to host finished."); - } else { - $message = ""; - } - } - - # As of now, the BackgroundProcessing thread posts status bar update messages to a queue on the MainFrame.pm, - # but the "Processing finished" message is posted to this window. - # Delay the following status bar update, so it will be called later than what is received by MainFrame.pm. - wxTheApp->CallAfter(sub { - $self->statusbar->SetStatusText($message); - }); - - $self->{print_file} = undef; - $self->{send_gcode_file} = undef; - $self->print_info_box_show(1); - - # this updates buttons status - $self->object_list_changed; - - # refresh preview - $self->{preview_iface}->reload_print if $self->{preview_iface}; -# $self->{preview3D}->reload_print if $self->{preview3D}; -} - -# XXX: partially done in the Sidebar -# Fill in the "Sliced info" box with the result of the G-code generator. -sub print_info_box_show { - my ($self, $show) = @_; -# my $scrolled_window_panel = $self->{scrolled_window_panel}; -# my $scrolled_window_sizer = $self->{scrolled_window_sizer}; -# return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show)); - my $panel = $self->{scrolled_window_panel};#$self->{right_panel}; - my $sizer = $self->{info_sizer}; -# return if (!$sizer || !$show && ($sizer->IsShown(1) == $show)); - return if (!$sizer); - - Slic3r::GUI::set_show_print_info($show); -# return if (wxTheApp->{app_config}->get("view_mode") eq "simple"); - -# if ($show) - { - my $print_info_sizer = $self->{print_info_sizer}; - $print_info_sizer->Clear(1); - my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5); - $grid_sizer->SetFlexibleDirection(wxHORIZONTAL); - $grid_sizer->AddGrowableCol(1, 1); - $grid_sizer->AddGrowableCol(3, 1); - $print_info_sizer->Add($grid_sizer, 0, wxEXPAND); - my $is_wipe_tower = $self->{print}->total_wipe_tower_filament > 0; - my @info = ( - L("Used Filament (m)") - => $is_wipe_tower ? - sprintf("%.2f (%.2f %s + %.2f %s)" , $self->{print}->total_used_filament / 1000, - ($self->{print}->total_used_filament - $self->{print}->total_wipe_tower_filament) / 1000, - L("objects"), - $self->{print}->total_wipe_tower_filament / 1000, - L("wipe tower")) : - sprintf("%.2f" , $self->{print}->total_used_filament / 1000), - - L("Used Filament (mm³)") - => sprintf("%.2f" , $self->{print}->total_extruded_volume), - L("Used Filament (g)"), - => sprintf("%.2f" , $self->{print}->total_weight), - L("Cost"), - => $is_wipe_tower ? - sprintf("%.2f (%.2f %s + %.2f %s)" , $self->{print}->total_cost, - ($self->{print}->total_cost - $self->{print}->total_wipe_tower_cost), - L("objects"), - $self->{print}->total_wipe_tower_cost, - L("wipe tower")) : - sprintf("%.2f" , $self->{print}->total_cost), - L("Estimated printing time (normal mode)") - => $self->{print}->estimated_normal_print_time, - L("Estimated printing time (silent mode)") - => $self->{print}->estimated_silent_print_time - ); - # if there is a wipe tower, insert number of toolchanges info into the array: - splice (@info, 8, 0, L("Number of tool changes") => sprintf("%.d", $self->{print}->wipe_tower_number_of_toolchanges)) if ($is_wipe_tower); - - while ( my $label = shift @info) { - my $value = shift @info; - next if $value eq "N/A"; -# my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - my $text = Wx::StaticText->new($panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - $text->SetFont($Slic3r::GUI::small_font); - $grid_sizer->Add($text, 0); -# my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - my $field = Wx::StaticText->new($panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - $field->SetFont($Slic3r::GUI::small_font); - $grid_sizer->Add($field, 0); - } - } - -# $scrolled_window_sizer->Show(2, $show); -# $scrolled_window_panel->Layout; - $sizer->Show(1, $show && wxTheApp->{app_config}->get("view_mode") ne "simple"); - - $self->Layout; - $panel->Refresh; -} - -# XXX: not done - to be removed -sub do_print { - my ($self) = @_; - - my $controller = $self->GetFrame->{controller}; - my $printer_preset = wxTheApp->{preset_bundle}->printer->get_edited_preset; - my $printer_panel = $controller->add_printer($printer_preset->name, $printer_preset->config); - - my $filament_stats = $self->{print}->filament_stats; - my $filament_names = wxTheApp->{preset_bundle}->filament_presets; - $filament_stats = { map { $filament_names->[$_] => $filament_stats->{$_} } keys %$filament_stats }; - $printer_panel->load_print_job($self->{print_file}, $filament_stats); -} - -# XXX: VK: done -sub export_stl { - my ($self) = @_; - return if !@{$self->{objects}}; - # Ask user for a file name to write into. - my $output_file = $self->_get_export_file('STL') or return; - # Store a binary STL. - $self->{model}->store_stl($output_file, 1); - $self->statusbar->SetStatusText(L("STL file exported to ").$output_file); -} - -# XXX: VK: done -sub reload_from_disk { - my ($self) = @_; - - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - - my $model_object = $self->{model}->objects->[$obj_idx]; - #FIXME convert to local file encoding - return if !$model_object->input_file - || !-e Slic3r::encode_path($model_object->input_file); - - my @new_obj_idx = $self->load_files([$model_object->input_file]); - return if !@new_obj_idx; - - foreach my $new_obj_idx (@new_obj_idx) { - my $o = $self->{model}->objects->[$new_obj_idx]; - $o->clear_instances; - $o->add_instance($_) for @{$model_object->instances}; - #$o->invalidate_bounding_box; - - if ($o->volumes_count == $model_object->volumes_count) { - for my $i (0..($o->volumes_count-1)) { - $o->get_volume($i)->config->apply($model_object->get_volume($i)->config); - } - } - #FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid, - } - - $self->remove($obj_idx); -} - -# XXX: VK: integrated into Plater::export_stl() -sub export_object_stl { - my ($self) = @_; - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - my $model_object = $self->{model}->objects->[$obj_idx]; - # Ask user for a file name to write into. - my $output_file = $self->_get_export_file('STL') or return; - $model_object->mesh->write_binary($output_file); - $self->statusbar->SetStatusText(L("STL file exported to ").$output_file); -} - -# XXX: not done -sub fix_through_netfabb { - my ($self) = @_; - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_fixed = Slic3r::Model->new; - Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed); - - my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects}); - return if !@new_obj_idx; - - foreach my $new_obj_idx (@new_obj_idx) { - my $o = $self->{model}->objects->[$new_obj_idx]; - $o->clear_instances; - $o->add_instance($_) for @{$model_object->instances}; - #$o->invalidate_bounding_box; - - if ($o->volumes_count == $model_object->volumes_count) { - for my $i (0..($o->volumes_count-1)) { - $o->get_volume($i)->config->apply($model_object->get_volume($i)->config); - } - } - #FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid, - } - - $self->remove($obj_idx); -} - -# XXX: VK: done -sub export_amf { - my ($self) = @_; - return if !@{$self->{objects}}; - # Ask user for a file name to write into. - my $output_file = $self->_get_export_file('AMF') or return; - my $res = $self->{model}->store_amf($output_file, $self->{print}, $self->{export_option}); - if ($res) - { - $self->statusbar->SetStatusText(L("AMF file exported to ").$output_file); - } - else - { - $self->statusbar->SetStatusText(L("Error exporting AMF file ").$output_file); - } -} - -# XXX: VK: done -sub export_3mf { - my ($self) = @_; - return if !@{$self->{objects}}; - # Ask user for a file name to write into. - my $output_file = $self->_get_export_file('3MF') or return; - my $res = $self->{model}->store_3mf($output_file, $self->{print}, $self->{export_option}); - if ($res) - { - $self->statusbar->SetStatusText(L("3MF file exported to ").$output_file); - } - else - { - $self->statusbar->SetStatusText(L("Error exporting 3MF file ").$output_file); - } -} - -# XXX: VK: done -# Ask user to select an output file for a given file format (STl, AMF, 3MF). -# Propose a default file name based on the 'output_filename_format' configuration value. -sub _get_export_file { - my ($self, $format) = @_; - my $suffix = ''; - my $wildcard = 'known'; - if ($format eq 'STL') - { - $suffix = '.stl'; - $wildcard = 'stl'; - } - elsif ($format eq 'AMF') - { - if (&Wx::wxMAC) { - # It seems that MacOS does not like double extension - $suffix = '.amf'; - } else { - $suffix = '.zip.amf'; - } - $wildcard = 'amf'; - } - elsif ($format eq '3MF') - { - $suffix = '.3mf'; - $wildcard = 'threemf'; - } - # Copy the names of active presets into the placeholder parser. - wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser); - my $output_file = eval { $self->{print}->output_filepath($main::opt{output} // '') }; - Slic3r::GUI::catch_error($self) and return undef; - $output_file =~ s/\.[gG][cC][oO][dD][eE]$/$suffix/; - my $dlg = Wx::FileDialog->new($self, L("Save ").$format.L(" file as:"), dirname($output_file), - basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{$wildcard}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - Slic3r::GUI::add_export_option($dlg, $format); - if ($dlg->ShowModal != wxID_OK) { - $dlg->Destroy; - return undef; - } - $output_file = $dlg->GetPath; - $self->{export_option} = Slic3r::GUI::get_export_option($dlg); - $dlg->Destroy; - return $output_file; -} - -#sub reset_thumbnail { -# my ($self, $obj_idx) = @_; -# $self->{objects}[$obj_idx]->thumbnail(undef); -#} - -# XXX: VK: done -# this method gets called whenever print center is changed or the objects' bounding box changes -# (i.e. when an object is added/removed/moved/rotated/scaled) -sub update { - my ($self, $force_autocenter) = @_; - $self->Freeze; - if (wxTheApp->{app_config}->get("autocenter") || $force_autocenter) { - $self->{model}->center_instances_around_point($self->bed_centerf); - } - $self->stop_background_process; - $self->{print}->reload_model_instances(); - $self->{canvas}->reload_scene if $self->{canvas}; -# $self->{canvas}->reload_scene if $self->{canvas}; - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0); - $self->{preview_iface}->reset_gcode_preview_data if $self->{preview_iface}; - $self->{preview_iface}->reload_print if $self->{preview_iface}; -# $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D}; -# $self->{preview3D}->reload_print if $self->{preview3D}; - $self->schedule_background_process; - $self->Thaw; -} - -# XXX: YS: done -# When a printer technology is changed, the UI needs to be updated to show/hide needed preset combo boxes. -sub show_preset_comboboxes{ - my ($self, $showSLA) = @_; #if showSLA is oposite value to "ptFFF" - - my $choices = $self->{preset_choosers}{filament}; - my $print_filament_ctrls_cnt = 2 + 2 * ($#$choices+1); - - foreach (0..$print_filament_ctrls_cnt-1){ - $self->{presets_sizer}->Show($_, !$showSLA); - } - $self->{presets_sizer}->Show($print_filament_ctrls_cnt , $showSLA); - $self->{presets_sizer}->Show($print_filament_ctrls_cnt+1, $showSLA); - - $self->{frequently_changed_parameters_sizer}->Show(0,!$showSLA); - - $self->Layout; -} - -# XXX: YS: done -# When a number of extruders changes, the UI needs to be updated to show a single filament selection combo box per extruder. -# Also the wxTheApp->{preset_bundle}->filament_presets needs to be resized accordingly -# and some reasonable default has to be selected for the additional extruders. -sub on_extruders_change { - my ($self, $num_extruders) = @_; - my $choices = $self->{preset_choosers}{filament}; - - while (int(@$choices) < $num_extruders) { - # copy strings from first choice - my @presets = $choices->[0]->GetStrings; - - # initialize new choice -# my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY); - my $choice = Wx::BitmapComboBox->new($self->{scrolled_window_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY); - my $extruder_idx = scalar @$choices; - EVT_LEFT_DOWN($choice, sub { $self->filament_color_box_lmouse_down($extruder_idx, @_); } ); - push @$choices, $choice; - # copy icons from first choice - $choice->SetItemBitmap($_, $choices->[0]->GetItemBitmap($_)) for 0..$#presets; - # insert new choice into sizer - $self->{presets_sizer}->Insert(4 + ($#$choices-1)*2, 0, 0); - $self->{presets_sizer}->Insert(5 + ($#$choices-1)*2, $choice, 0, wxEXPAND | wxBOTTOM, 0); - # setup the listener - EVT_COMBOBOX($choice, $choice, sub { - my ($choice) = @_; - wxTheApp->CallAfter(sub { - $self->_on_select_preset('filament', $choice, $extruder_idx); - }); - }); - # initialize selection - wxTheApp->{preset_bundle}->update_platter_filament_ui($extruder_idx, $choice); - } - - # remove unused choices if any - while (@$choices > $num_extruders) { - $self->{presets_sizer}->Remove(4 + ($#$choices-1)*2); # label - $self->{presets_sizer}->Remove(4 + ($#$choices-1)*2); # wxChoice - $choices->[-1]->Destroy; - pop @$choices; - } - $self->{right_panel}->Layout; - $self->Layout; -} - -# XXX: not done -sub on_config_change { - my ($self, $config) = @_; - - my $update_scheduled; - foreach my $opt_key (@{$self->{config}->diff($config)}) { - $self->{config}->set($opt_key, $config->get($opt_key)); - if ($opt_key eq 'bed_shape') { -# $self->{canvas}->update_bed_size; - Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D}; - $self->{preview_iface}->set_bed_shape($self->{config}->bed_shape) if ($self->{preview_iface}); -# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D}; - $update_scheduled = 1; - } elsif ($opt_key =~ '^wipe_tower' || $opt_key eq 'single_extruder_multi_material') { - $update_scheduled = 1; - } elsif ($opt_key eq 'serial_port') { - $self->{btn_print}->Show($config->get('serial_port')); - $self->Layout; - } elsif ($opt_key eq 'print_host') { - $self->{btn_send_gcode}->Show($config->get('print_host')); - $self->Layout; - } elsif ($opt_key eq 'variable_layer_height') { - if ($config->get('variable_layer_height') != 1) { -# if ($self->{htoolbar}) { -# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0); -# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0); -# } else { -# $self->{"btn_layer_editing"}->Disable; -# $self->{"btn_layer_editing"}->SetValue(0); -# } - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 0); - Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, 0); - $self->{canvas3D}->Refresh; - $self->{canvas3D}->Update; - } elsif (Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D})) { - # Want to allow the layer editing, but do it only if the OpenGL supports it. -# if ($self->{htoolbar}) { -# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1); -# } else { -# $self->{"btn_layer_editing"}->Enable; -# } - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 1); - } - } elsif ($opt_key eq 'extruder_colour') { - $update_scheduled = 1; - my $extruder_colors = $config->get('extruder_colour'); - $self->{preview_iface}->set_number_extruders(scalar(@{$extruder_colors})); -# $self->{preview3D}->set_number_extruders(scalar(@{$extruder_colors})); - } elsif ($opt_key eq 'max_print_height') { - $update_scheduled = 1; - } elsif ($opt_key eq 'printer_model') { - # update to force bed selection (for texturing) - Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D}; - $self->{preview_iface}->set_bed_shape($self->{config}->bed_shape) if ($self->{preview_iface}); -# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D}; - $update_scheduled = 1; - } - } - - $self->update if $update_scheduled; - - return if !$self->GetFrame->is_loaded; - - # (re)start timer - $self->schedule_background_process; -} - -# XXX: YS: WIP -sub item_changed_selection { - my ($self, $obj_idx) = @_; - - if (($obj_idx >= 0) && ($obj_idx < 1000)) { # skip if wipe tower selected - if ($self->{canvas3D}) { - Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}); - if ($obj_idx >= 0) { - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections); - } -# Slic3r::GUI::_3DScene::render($self->{canvas3D}); - } - } -} - -# XXX: VK: done -sub collect_selections { - my ($self) = @_; - my $selections = []; - foreach my $o (@{$self->{objects}}) { - push(@$selections, $o->selected); - } - return $selections; -} - -# XXX: YS: done, lambda on LEFT_DOWN -# Called when clicked on the filament preset combo box. -# When clicked on the icon, show the color picker. -sub filament_color_box_lmouse_down -{ - my ($self, $extruder_idx, $combobox, $event) = @_; - my $pos = $event->GetLogicalPosition(Wx::ClientDC->new($combobox)); - my( $x, $y ) = ( $pos->x, $pos->y ); - if ($x > 24) { - # Let the combo box process the mouse click. - $event->Skip; - } else { - # Swallow the mouse click and open the color picker. - my $data = Wx::ColourData->new; - $data->SetChooseFull(1); - my $dialog = Wx::ColourDialog->new($self->GetFrame, $data); - if ($dialog->ShowModal == wxID_OK) { - my $cfg = Slic3r::Config->new; - my $colors = wxTheApp->{preset_bundle}->full_config->get('extruder_colour'); - $colors->[$extruder_idx] = $dialog->GetColourData->GetColour->GetAsString(wxC2S_HTML_SYNTAX); - $cfg->set('extruder_colour', $colors); - $self->GetFrame->{options_tabs}{printer}->load_config($cfg); - wxTheApp->{preset_bundle}->update_platter_filament_ui($extruder_idx, $combobox); - } - $dialog->Destroy(); - } -} - -#sub object_cut_dialog { -# my ($self, $obj_idx) = @_; -# -# if (!defined $obj_idx) { -# ($obj_idx, undef) = $self->selected_object; -# } -# -# if (!$Slic3r::GUI::have_OpenGL) { -# Slic3r::GUI::show_error($self, L("Please install the OpenGL modules to use this feature (see build instructions).")); -# return; -# } -# -# my $dlg = Slic3r::GUI::Plater::ObjectCutDialog->new($self, -# object => $self->{objects}[$obj_idx], -# model_object => $self->{model}->objects->[$obj_idx], -# ); -# return unless $dlg->ShowModal == wxID_OK; -# -# if (my @new_objects = $dlg->NewModelObjects) { -# $self->remove($obj_idx); -# $self->load_model_objects(grep defined($_), @new_objects); -# $self->arrange; -# Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D}; -# } -#} - -# XXX: YS: done -sub changed_object_settings { - my ($self, $obj_idx, $parts_changed, $part_settings_changed) = @_; - - # update thumbnail since parts may have changed - if ($parts_changed) { - # recenter and re-align to Z = 0 - my $model_object = $self->{model}->objects->[$obj_idx]; - $model_object->center_around_origin; -# $self->reset_thumbnail($obj_idx); - } - - # update print - if ($parts_changed || $part_settings_changed) { - $self->stop_background_process; - $self->{print}->reload_object($obj_idx); - $self->schedule_background_process; - $self->{canvas}->reload_scene if $self->{canvas}; - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0); - } else { - $self->schedule_background_process; - } -} - -# XXX: VK: done -# Called to update various buttons depending on whether there are any objects or -# whether background processing (export of a G-code, sending to Octoprint, forced background re-slicing) is active. -sub object_list_changed { - my $self = shift; - - # Enable/disable buttons depending on whether there are any objects on the platter. - my $have_objects = @{$self->{objects}} ? 1 : 0; -# if ($self->{htoolbar}) { -# # On OSX or Linux -# $self->{htoolbar}->EnableTool($_, $have_objects) -# for (TB_RESET, TB_ARRANGE); -# } else { -# # On MSW -# my $method = $have_objects ? 'Enable' : 'Disable'; -# $self->{"btn_$_"}->$method -# for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode); -# } - - for my $toolbar_item (qw(deleteall arrange)) { - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, $toolbar_item, $have_objects); - } - - my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file}; - my $model_fits = $self->{canvas3D} ? Slic3r::GUI::_3DScene::check_volumes_outside_state($self->{canvas3D}, $self->{config}) : 1; - # $model_fits == 1 -> ModelInstance::PVS_Partly_Outside - my $method = ($have_objects && ! $export_in_progress && ($model_fits != 1)) ? 'Enable' : 'Disable'; - $self->{"btn_$_"}->$method - for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode); -} - -# XXX: VK: WIP -# Selection of an active 3D object changed. -sub selection_changed { - my ($self) = @_; - my ($obj_idx, $object) = $self->selected_object; - my $have_sel = defined $obj_idx; - my $layers_height_allowed = $self->{config}->variable_layer_height && Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D}) && $have_sel; - - $self->{right_panel}->Freeze; -# if ($self->{htoolbar}) { -# # On OSX or Linux -# $self->{htoolbar}->EnableTool($_, $have_sel) -# for (TB_REMOVE, TB_MORE, TB_45CW, TB_45CCW, TB_SCALE, TB_SPLIT, TB_CUT, TB_SETTINGS); -# -# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, $layers_height_allowed); -# -# if ($have_sel) { -# my $model_object = $self->{model}->objects->[$obj_idx]; -# $self->{htoolbar}->EnableTool(TB_FEWER, $model_object->instances_count > 1); -# } else { -# $self->{htoolbar}->EnableTool(TB_FEWER, 0); -# } -# -# } else { -# # On MSW -# my $method = $have_sel ? 'Enable' : 'Disable'; -# $self->{"btn_$_"}->$method -# for grep $self->{"btn_$_"}, qw(remove increase rotate45cw rotate45ccw changescale split cut settings); -# -# if ($layers_height_allowed) { -# $self->{"btn_layer_editing"}->Enable; -# } else { -# $self->{"btn_layer_editing"}->Disable; -# } -# -# if ($have_sel) { -# my $model_object = $self->{model}->objects->[$obj_idx]; -# if ($model_object->instances_count > 1) { -# $self->{"btn_decrease"}->Enable; -# } else { -# $self->{"btn_decrease"}->Disable; -# } -# } else { -# $self->{"btn_decrease"}->Disable; -# } -# } - - for my $toolbar_item (qw(delete more fewer split cut settings)) { - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, $toolbar_item, $have_sel); - } - - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", $layers_height_allowed); - - my $can_select_by_parts = 0; - - if ($have_sel) { - my $model_object = $self->{model}->objects->[$obj_idx]; - $can_select_by_parts = ($obj_idx >= 0) && ($obj_idx < 1000) && ($model_object->volumes_count > 1); - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "fewer", $model_object->instances_count > 1); - } - - if ($can_select_by_parts) { - # first disable to let the item in the toolbar to switch to the unpressed state - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "selectbyparts", 0); - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "selectbyparts", 1); - } else { - Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "selectbyparts", 0); - Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object'); - } - - if ($self->{object_info_size}) { # have we already loaded the info pane? - if ($have_sel) { - my $model_object = $self->{model}->objects->[$obj_idx]; - #FIXME print_info runs model fixing in two rounds, it is very slow, it should not be performed here! - # $model_object->print_info; - my $model_instance = $model_object->instances->[0]; - $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", @{$model_object->instance_bounding_box(0)->size})); - $self->{object_info_materials}->SetLabel($model_object->materials_count); - - if (my $stats = $model_object->mesh_stats) { - $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * ($model_instance->scaling_factor**3))); - $self->{object_info_facets}->SetLabel(sprintf(L('%d (%d shells)'), $model_object->facets_count, $stats->{number_of_parts})); - if (my $errors = sum(@$stats{qw(degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges)})) { - $self->{object_info_manifold}->SetLabel(sprintf(L("Auto-repaired (%d errors)"), $errors)); - #$self->{object_info_manifold_warning_icon}->Show; - $self->{"object_info_manifold_warning_icon_show"}->(1); - - # we don't show normals_fixed because we never provide normals - # to admesh, so it generates normals for all facets - my $message = sprintf L('%d degenerate facets, %d edges fixed, %d facets removed, %d facets added, %d facets reversed, %d backwards edges'), - @$stats{qw(degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges)}; - $self->{object_info_manifold}->SetToolTipString($message); - $self->{object_info_manifold_warning_icon}->SetToolTipString($message); - } else { - $self->{object_info_manifold}->SetLabel(L("Yes")); - #$self->{object_info_manifold_warning_icon}->Hide; - $self->{"object_info_manifold_warning_icon_show"}->(0); - $self->{object_info_manifold}->SetToolTipString(""); - $self->{object_info_manifold_warning_icon}->SetToolTipString(""); - } - } else { - $self->{object_info_facets}->SetLabel($object->facets); - } - } else { - $self->{"object_info_$_"}->SetLabel("") for qw(size volume facets materials manifold); - #$self->{object_info_manifold_warning_icon}->Hide; - $self->{"object_info_manifold_warning_icon_show"}->(0); - $self->{object_info_manifold}->SetToolTipString(""); - $self->{object_info_manifold_warning_icon}->SetToolTipString(""); - } - $self->Layout; - } - - # prepagate the event to the frame (a custom Wx event would be cleaner) - $self->GetFrame->on_plater_selection_changed($have_sel); - $self->{right_panel}->Thaw; -} - -# XXX: VK: done -sub select_object { - my ($self, $obj_idx, $child) = @_; - - # remove current selection - foreach my $o (0..$#{$self->{objects}}) { - $self->{objects}->[$o]->selected(0); - } - - if (defined $obj_idx) { - $self->{objects}->[$obj_idx]->selected(1); - # Select current object in the list on c++ side, if item isn't child -# if (!defined $child){ -# Slic3r::GUI::select_current_object($obj_idx);} # all selections in the object list is on c++ side - } else { - # Unselect all objects in the list on c++ side -# Slic3r::GUI::unselect_objects(); # all selections in the object list is on c++ side - } - $self->selection_changed(1); -} - -# XXX: YS: WIP -sub select_object_from_cpp { - my ($self, $obj_idx, $vol_idx) = @_; - - # remove current selection - foreach my $o (0..$#{$self->{objects}}) { - $self->{objects}->[$o]->selected(0); - } - - my $curr = Slic3r::GUI::_3DScene::get_select_by($self->{canvas3D}); - - if (defined $obj_idx) { - if ($vol_idx == -1){ - if ($curr eq 'object') { - $self->{objects}->[$obj_idx]->selected(1); - } - elsif ($curr eq 'volume') { - Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object'); - } - - my $selections = $self->collect_selections; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); - } - else { - if ($curr eq 'object') { - Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'volume'); - } - - my $selections = []; - Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); - Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}); - Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); - my $volume_idx = Slic3r::GUI::_3DScene::get_first_volume_id($self->{canvas3D}, $obj_idx); - - my $inst_cnt = $self->{model}->objects->[$obj_idx]->instances_count; - for (0..$inst_cnt-1){ - Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx*$inst_cnt + $_ + $volume_idx) if ($volume_idx != -1); - } - } - } - - $self->selection_changed(1); -} - -# XXX: VK: done -sub selected_object { - my ($self) = @_; - my $obj_idx = first { $self->{objects}[$_]->selected } 0..$#{ $self->{objects} }; - return defined $obj_idx ? ($obj_idx, $self->{objects}[$obj_idx]) : undef; -} - -# XXX: VK: done -sub statusbar { - return $_[0]->GetFrame->{statusbar}; -} - -# XXX: not done, to be removed (?) -sub object_menu { - my ($self) = @_; - - my $frame = $self->GetFrame; - my $menu = Wx::Menu->new; - my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] }; - $frame->_append_menu_item($menu, $accel->(L('Delete'), 'Del'), L('Remove the selected object'), sub { - $self->remove; - }, undef, 'brick_delete.png'); - $frame->_append_menu_item($menu, $accel->(L('Increase copies'), '+'), L('Place one more copy of the selected object'), sub { - $self->increase; - }, undef, 'add.png'); - $frame->_append_menu_item($menu, $accel->(L('Decrease copies'), '-'), L('Remove one copy of the selected object'), sub { - $self->decrease; - }, undef, 'delete.png'); - $frame->_append_menu_item($menu, L("Set number of copies…"), L('Change the number of copies of the selected object'), sub { - $self->set_number_of_copies; - }, undef, 'textfield.png'); - $menu->AppendSeparator(); - $frame->_append_menu_item($menu, $accel->(L('Rotate 45° clockwise'), 'l'), L('Rotate the selected object by 45° clockwise'), sub { - $self->rotate(-45, Z, 'relative'); - }, undef, 'arrow_rotate_clockwise.png'); - $frame->_append_menu_item($menu, $accel->(L('Rotate 45° counter-clockwise'), 'r'), L('Rotate the selected object by 45° counter-clockwise'), sub { - $self->rotate(+45, Z, 'relative'); - }, undef, 'arrow_rotate_anticlockwise.png'); - - my $rotateMenu = Wx::Menu->new; - my $rotateMenuItem = $menu->AppendSubMenu($rotateMenu, L("Rotate"), L('Rotate the selected object by an arbitrary angle')); - $frame->_set_menu_item_icon($rotateMenuItem, 'textfield.png'); - $frame->_append_menu_item($rotateMenu, L("Around X axis…"), L('Rotate the selected object by an arbitrary angle around X axis'), sub { - $self->rotate(undef, X); - }, undef, 'bullet_red.png'); - $frame->_append_menu_item($rotateMenu, L("Around Y axis…"), L('Rotate the selected object by an arbitrary angle around Y axis'), sub { - $self->rotate(undef, Y); - }, undef, 'bullet_green.png'); - $frame->_append_menu_item($rotateMenu, L("Around Z axis…"), L('Rotate the selected object by an arbitrary angle around Z axis'), sub { - $self->rotate(undef, Z); - }, undef, 'bullet_blue.png'); - - my $mirrorMenu = Wx::Menu->new; - my $mirrorMenuItem = $menu->AppendSubMenu($mirrorMenu, L("Mirror"), L('Mirror the selected object')); - $frame->_set_menu_item_icon($mirrorMenuItem, 'shape_flip_horizontal.png'); - $frame->_append_menu_item($mirrorMenu, L("Along X axis…"), L('Mirror the selected object along the X axis'), sub { - $self->mirror(X); - }, undef, 'bullet_red.png'); - $frame->_append_menu_item($mirrorMenu, L("Along Y axis…"), L('Mirror the selected object along the Y axis'), sub { - $self->mirror(Y); - }, undef, 'bullet_green.png'); - $frame->_append_menu_item($mirrorMenu, L("Along Z axis…"), L('Mirror the selected object along the Z axis'), sub { - $self->mirror(Z); - }, undef, 'bullet_blue.png'); - - my $scaleMenu = Wx::Menu->new; - my $scaleMenuItem = $menu->AppendSubMenu($scaleMenu, L("Scale"), L('Scale the selected object along a single axis')); - $frame->_set_menu_item_icon($scaleMenuItem, 'arrow_out.png'); - $frame->_append_menu_item($scaleMenu, $accel->(L('Uniformly…'), 's'), L('Scale the selected object along the XYZ axes'), sub { - $self->changescale(undef); - }); - $frame->_append_menu_item($scaleMenu, L("Along X axis…"), L('Scale the selected object along the X axis'), sub { - $self->changescale(X); - }, undef, 'bullet_red.png'); - $frame->_append_menu_item($scaleMenu, L("Along Y axis…"), L('Scale the selected object along the Y axis'), sub { - $self->changescale(Y); - }, undef, 'bullet_green.png'); - $frame->_append_menu_item($scaleMenu, L("Along Z axis…"), L('Scale the selected object along the Z axis'), sub { - $self->changescale(Z); - }, undef, 'bullet_blue.png'); - - my $scaleToSizeMenu = Wx::Menu->new; - my $scaleToSizeMenuItem = $menu->AppendSubMenu($scaleToSizeMenu, L("Scale to size"), L('Scale the selected object along a single axis')); - $frame->_set_menu_item_icon($scaleToSizeMenuItem, 'arrow_out.png'); - $frame->_append_menu_item($scaleToSizeMenu, L("Uniformly…"), L('Scale the selected object along the XYZ axes'), sub { - $self->changescale(undef, 1); - }); - $frame->_append_menu_item($scaleToSizeMenu, L("Along X axis…"), L('Scale the selected object along the X axis'), sub { - $self->changescale(X, 1); - }, undef, 'bullet_red.png'); - $frame->_append_menu_item($scaleToSizeMenu, L("Along Y axis…"), L('Scale the selected object along the Y axis'), sub { - $self->changescale(Y, 1); - }, undef, 'bullet_green.png'); - $frame->_append_menu_item($scaleToSizeMenu, L("Along Z axis…"), L('Scale the selected object along the Z axis'), sub { - $self->changescale(Z, 1); - }, undef, 'bullet_blue.png'); - - $frame->_append_menu_item($menu, L("Split"), L('Split the selected object into individual parts'), sub { - $self->split_object; - }, undef, 'shape_ungroup.png'); - $frame->_append_menu_item($menu, L("Cut…"), L('Open the 3D cutting tool'), sub { - $self->object_cut_dialog; - }, undef, 'package.png'); - $menu->AppendSeparator(); - $frame->_append_menu_item($menu, L("Settings…"), L('Open the object editor dialog'), sub { - $self->object_settings_dialog; - }, undef, 'cog.png'); - $menu->AppendSeparator(); - $frame->_append_menu_item($menu, L("Reload from Disk"), L('Reload the selected file from Disk'), sub { - $self->reload_from_disk; - }, undef, 'arrow_refresh.png'); - $frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub { - $self->export_object_stl; - }, undef, 'brick_go.png'); - if (Slic3r::GUI::is_windows10) { - $frame->_append_menu_item($menu, L("Fix STL through Netfabb"), L('Fix the model by sending it to a Netfabb cloud service through Windows 10 API'), sub { - $self->fix_through_netfabb; - }, undef, 'brick_go.png'); - } - - return $menu; -} - -# XXX: not done -# Set a camera direction, zoom to all objects. -sub select_view { - my ($self, $direction) = @_; - my $idx_page = $self->{preview_notebook}->GetSelection; - my $page = ($idx_page == &Wx::wxNOT_FOUND) ? L('3D') : $self->{preview_notebook}->GetPageText($idx_page); - if ($page eq L('Preview')) { - $self->{preview_iface}->select_view($direction); - $self->{preview_iface}->set_viewport_into_scene($self->{canvas3D}); -# Slic3r::GUI::_3DScene::select_view($self->{preview3D}->canvas, $direction); -# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); - } else { - Slic3r::GUI::_3DScene::select_view($self->{canvas3D}, $direction); - $self->{preview_iface}->set_viewport_from_scene($self->{canvas3D}); -# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); - } -} - - -# XXX: VK: done, in PlaterDropTarget -package Slic3r::GUI::Plater::DropTarget; -use Wx::DND; -use base 'Wx::FileDropTarget'; - -sub new { - my ($class, $window) = @_; - my $self = $class->SUPER::new; - $self->{window} = $window; - return $self; -} - -sub OnDropFiles { - my ($self, $x, $y, $filenames) = @_; - # stop scalars leaking on older perl - # https://rt.perl.org/rt3/Public/Bug/Display.html?id=70602 - @_ = (); - # only accept STL, OBJ, AMF, 3MF and PRUSA files - return 0 if grep !/\.(?:[sS][tT][lL]|[oO][bB][jJ]|[aA][mM][fF]|[3][mM][fF]|[aA][mM][fF].[xX][mM][lL]|[zZ][iI][pP].[aA][mM][lL]|[pP][rR][uU][sS][aA])$/, @$filenames; - $self->{window}->load_files($filenames); -} - -# 2D preview of an object. Each object is previewed by its convex hull. -package Slic3r::GUI::Plater::Object; -use Moo; - -has 'name' => (is => 'rw', required => 1); -has 'selected' => (is => 'rw', default => sub { 0 }); - -1; diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm deleted file mode 100644 index 0b770b31c..000000000 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ /dev/null @@ -1,26 +0,0 @@ -package Slic3r::GUI::Plater::3D; -use strict; -use warnings; -use utf8; - -use List::Util qw(); -use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL); -use base qw(Slic3r::GUI::3DScene Class::Accessor); - -sub new { - my $class = shift; - my ($parent, $objects, $model, $print, $config) = @_; - - my $self = $class->SUPER::new($parent); - Slic3r::GUI::_3DScene::enable_picking($self, 1); - Slic3r::GUI::_3DScene::enable_moving($self, 1); - Slic3r::GUI::_3DScene::set_select_by($self, 'object'); - Slic3r::GUI::_3DScene::set_drag_by($self, 'instance'); - Slic3r::GUI::_3DScene::set_model($self, $model); - Slic3r::GUI::_3DScene::set_print($self, $print); - Slic3r::GUI::_3DScene::set_config($self, $config); - - return $self; -} - -1; diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm deleted file mode 100644 index bc229723c..000000000 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ /dev/null @@ -1,566 +0,0 @@ -package Slic3r::GUI::Plater::3DPreview; -use strict; -use warnings; -use utf8; - -use Slic3r::Print::State ':steps'; -use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxCB_READONLY); -use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX EVT_SIZE); -use base qw(Wx::Panel Class::Accessor); - -use Wx::Locale gettext => 'L'; - -__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer double_slider_sizer)); - -sub new { - my $class = shift; - my ($parent, $print, $gcode_preview_data, $config) = @_; - - my $self = $class->SUPER::new($parent, -1, wxDefaultPosition); - $self->{config} = $config; - $self->{number_extruders} = 1; - # Show by feature type by default. - $self->{preferred_color_mode} = 'feature'; - - # init GUI elements - my $canvas = Slic3r::GUI::3DScene->new($self); - Slic3r::GUI::_3DScene::enable_shader($canvas, 1); - Slic3r::GUI::_3DScene::set_config($canvas, $config); - $self->canvas($canvas); -# my $slider_low = Wx::Slider->new( -# $self, -1, -# 0, # default -# 0, # min - # we set max to a bogus non-zero value because the MSW implementation of wxSlider - # will skip drawing the slider if max <= min: -# 1, # max -# wxDefaultPosition, -# wxDefaultSize, -# wxVERTICAL | wxSL_INVERSE, -# ); -# $self->slider_low($slider_low); -# my $slider_high = Wx::Slider->new( -# $self, -1, -# 0, # default -# 0, # min - # we set max to a bogus non-zero value because the MSW implementation of wxSlider - # will skip drawing the slider if max <= min: -# 1, # max -# wxDefaultPosition, -# wxDefaultSize, -# wxVERTICAL | wxSL_INVERSE, -# ); -# $self->slider_high($slider_high); - -# my $z_label_low = $self->{z_label_low} = Wx::StaticText->new($self, -1, "", wxDefaultPosition, -# [40,-1], wxALIGN_CENTRE_HORIZONTAL); -# $z_label_low->SetFont($Slic3r::GUI::small_font); -# my $z_label_high = $self->{z_label_high} = Wx::StaticText->new($self, -1, "", wxDefaultPosition, -# [40,-1], wxALIGN_CENTRE_HORIZONTAL); -# $z_label_high->SetFont($Slic3r::GUI::small_font); - -# my $z_label_low_idx = $self->{z_label_low_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition, -# [40,-1], wxALIGN_CENTRE_HORIZONTAL); -# $z_label_low_idx->SetFont($Slic3r::GUI::small_font); -# my $z_label_high_idx = $self->{z_label_high_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition, -# [40,-1], wxALIGN_CENTRE_HORIZONTAL); -# $z_label_high_idx->SetFont($Slic3r::GUI::small_font); - -# $self->single_layer(0); -# my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, L("1 Layer")); - - my $label_view_type = $self->{label_view_type} = Wx::StaticText->new($self, -1, L("View")); - - my $choice_view_type = $self->{choice_view_type} = Wx::Choice->new($self, -1); - $choice_view_type->Append(L("Feature type")); - $choice_view_type->Append(L("Height")); - $choice_view_type->Append(L("Width")); - $choice_view_type->Append(L("Speed")); - $choice_view_type->Append(L("Volumetric flow rate")); - $choice_view_type->Append(L("Tool")); - $choice_view_type->Append(L("Filament")); - $choice_view_type->SetSelection(0); - - # the following value needs to be changed if new items are added into $choice_view_type before "Tool" - $self->{tool_idx} = 5; - $self->{filament_idx} = 6; - - my $label_show_features = $self->{label_show_features} = Wx::StaticText->new($self, -1, L("Show")); - - my $combochecklist_features = $self->{combochecklist_features} = Wx::ComboCtrl->new(); - $combochecklist_features->Create($self, -1, L("Feature types"), wxDefaultPosition, [200, -1], wxCB_READONLY); - my $feature_text = L("Feature types"); - my $feature_items = L("Perimeter")."|" - .L("External perimeter")."|" - .L("Overhang perimeter")."|" - .L("Internal infill")."|" - .L("Solid infill")."|" - .L("Top solid infill")."|" - .L("Bridge infill")."|" - .L("Gap fill")."|" - .L("Skirt")."|" - .L("Support material")."|" - .L("Support material interface")."|" - .L("Wipe tower")."|" - .L("Custom"); - Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1); - - my $double_slider_sizer = Wx::BoxSizer->new(wxHORIZONTAL); - Slic3r::GUI::create_double_slider($self, $double_slider_sizer, $self->canvas); - $self->double_slider_sizer($double_slider_sizer); - - my $checkbox_travel = $self->{checkbox_travel} = Wx::CheckBox->new($self, -1, L("Travel")); - my $checkbox_retractions = $self->{checkbox_retractions} = Wx::CheckBox->new($self, -1, L("Retractions")); - my $checkbox_unretractions = $self->{checkbox_unretractions} = Wx::CheckBox->new($self, -1, L("Unretractions")); - my $checkbox_shells = $self->{checkbox_shells} = Wx::CheckBox->new($self, -1, L("Shells")); - -# my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); -# my $vsizer = Wx::BoxSizer->new(wxVERTICAL); -# my $vsizer_outer = Wx::BoxSizer->new(wxVERTICAL); -# $vsizer->Add($slider_low, 3, wxALIGN_CENTER_HORIZONTAL, 0); -# $vsizer->Add($z_label_low_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0); -# $vsizer->Add($z_label_low, 0, wxALIGN_CENTER_HORIZONTAL, 0); -# $hsizer->Add($vsizer, 0, wxEXPAND, 0); -# $vsizer = Wx::BoxSizer->new(wxVERTICAL); -# $vsizer->Add($slider_high, 3, wxALIGN_CENTER_HORIZONTAL, 0); -# $vsizer->Add($z_label_high_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0); -# $vsizer->Add($z_label_high, 0, 0, 0); -# $hsizer->Add($vsizer, 0, wxEXPAND, 0); -# $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0); -# $vsizer_outer->Add($double_slider_sizer, 3, wxEXPAND, 0); -# $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); - - my $bottom_sizer = Wx::BoxSizer->new(wxHORIZONTAL); - $bottom_sizer->Add($label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->AddSpacer(10); - $bottom_sizer->Add($label_show_features, 0, wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->Add($combochecklist_features, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->AddSpacer(20); - $bottom_sizer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->AddSpacer(10); - $bottom_sizer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->AddSpacer(10); - $bottom_sizer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $bottom_sizer->AddSpacer(10); - $bottom_sizer->Add($checkbox_shells, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - - my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); - $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0); -# $sizer->Add($vsizer_outer, 0, wxTOP | wxBOTTOM | wxEXPAND, 5); - $sizer->Add($double_slider_sizer, 0, wxEXPAND, 0);#wxTOP | wxBOTTOM | wxEXPAND, 5); - - my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); - $main_sizer->Add($sizer, 1, wxALL | wxEXPAND, 0); - $main_sizer->Add($bottom_sizer, 0, wxALL | wxEXPAND, 0); - -# EVT_SLIDER($self, $slider_low, sub { -# $slider_high->SetValue($slider_low->GetValue) if $self->single_layer; -# $self->set_z_idx_low ($slider_low ->GetValue) -# }); -# EVT_SLIDER($self, $slider_high, sub { -# $slider_low->SetValue($slider_high->GetValue) if $self->single_layer; -# $self->set_z_idx_high($slider_high->GetValue) -# }); -# EVT_KEY_DOWN($canvas, sub { -# my ($s, $event) = @_; -# Slic3r::GUI::update_double_slider_from_canvas($event); -# my $key = $event->GetKeyCode; -# if ($event->HasModifiers) { -# $event->Skip; -# } else { -# if ($key == ord('U')) { -# $slider_high->SetValue($slider_high->GetValue + 1); -# $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown()); -# $self->set_z_idx_high($slider_high->GetValue); -# } elsif ($key == ord('D')) { -# $slider_high->SetValue($slider_high->GetValue - 1); -# $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown()); -# $self->set_z_idx_high($slider_high->GetValue); -# } elsif ($key == ord('S')) { -# $checkbox_singlelayer->SetValue(! $checkbox_singlelayer->GetValue()); -# $self->single_layer($checkbox_singlelayer->GetValue()); -# if ($self->single_layer) { -# $slider_low->SetValue($slider_high->GetValue); -# $self->set_z_idx_high($slider_high->GetValue); -# } -# } else { -# $event->Skip; -# } -# } -# }); -# EVT_KEY_DOWN($slider_low, sub { -# my ($s, $event) = @_; -# my $key = $event->GetKeyCode; -# if ($event->HasModifiers) { -# $event->Skip; -# } else { -# if ($key == WXK_LEFT) { -# } elsif ($key == WXK_RIGHT) { -# $slider_high->SetFocus; -# } else { -# $event->Skip; -# } -# } -# }); -# EVT_KEY_DOWN($slider_high, sub { -# my ($s, $event) = @_; -# my $key = $event->GetKeyCode; -# if ($event->HasModifiers) { -# $event->Skip; -# } else { -# if ($key == WXK_LEFT) { -# $slider_low->SetFocus; -# } elsif ($key == WXK_RIGHT) { -# } else { -# $event->Skip; -# } -# } -# }); -# EVT_CHECKBOX($self, $checkbox_singlelayer, sub { -# $self->single_layer($checkbox_singlelayer->GetValue()); -# if ($self->single_layer) { -# $slider_low->SetValue($slider_high->GetValue); -# $self->set_z_idx_high($slider_high->GetValue); -# } -# }); - EVT_CHOICE($self, $choice_view_type, sub { - my $selection = $choice_view_type->GetCurrentSelection(); - $self->{preferred_color_mode} = ($selection == $self->{tool_idx}) ? 'tool' : 'feature'; - $self->gcode_preview_data->set_type($selection); - $self->reload_print; - }); - EVT_CHECKLISTBOX($self, $combochecklist_features, sub { - my $flags = Slic3r::GUI::combochecklist_get_flags($combochecklist_features); - - $self->gcode_preview_data->set_extrusion_flags($flags); - $self->refresh_print; - }); - EVT_CHECKBOX($self, $checkbox_travel, sub { - $self->gcode_preview_data->set_travel_visible($checkbox_travel->IsChecked()); - $self->refresh_print; - }); - EVT_CHECKBOX($self, $checkbox_retractions, sub { - $self->gcode_preview_data->set_retractions_visible($checkbox_retractions->IsChecked()); - $self->refresh_print; - }); - EVT_CHECKBOX($self, $checkbox_unretractions, sub { - $self->gcode_preview_data->set_unretractions_visible($checkbox_unretractions->IsChecked()); - $self->refresh_print; - }); - EVT_CHECKBOX($self, $checkbox_shells, sub { - $self->gcode_preview_data->set_shells_visible($checkbox_shells->IsChecked()); - $self->refresh_print; - }); - - EVT_SIZE($self, sub { - my ($s, $event) = @_; - $event->Skip; - $self->Refresh; - }); - - $self->SetSizer($main_sizer); - $self->SetMinSize($self->GetSize); - $sizer->SetSizeHints($self); - - # init canvas - $self->print($print); - $self->gcode_preview_data($gcode_preview_data); - - # sets colors for gcode preview extrusion roles - my @extrusion_roles_colors = ( - 'Perimeter' => 'FFFF66', - 'External perimeter' => 'FFA500', - 'Overhang perimeter' => '0000FF', - 'Internal infill' => 'B1302A', - 'Solid infill' => 'D732D7', - 'Top solid infill' => 'FF1A1A', - 'Bridge infill' => '9999FF', - 'Gap fill' => 'FFFFFF', - 'Skirt' => '845321', - 'Support material' => '00FF00', - 'Support material interface' => '008000', - 'Wipe tower' => 'B3E3AB', - 'Custom' => '28CC94', - ); - $self->gcode_preview_data->set_extrusion_paths_colors(\@extrusion_roles_colors); - - $self->show_hide_ui_elements('none'); - $self->reload_print; - - return $self; -} - -sub reload_print { - my ($self, $force) = @_; - - Slic3r::GUI::_3DScene::reset_volumes($self->canvas); - $self->_loaded(0); - - if (! $self->IsShown && ! $force) { -# $self->{reload_delayed} = 1; - return; - } - - $self->load_print; -} - -sub refresh_print { - my ($self) = @_; - - $self->_loaded(0); - - if (! $self->IsShown) { - return; - } - - $self->load_print; -} - -sub reset_gcode_preview_data { - my ($self) = @_; - $self->gcode_preview_data->reset; - Slic3r::GUI::_3DScene::reset_legend_texture(); -} - -sub load_print { - my ($self) = @_; - - return if $self->_loaded; - - # we require that there's at least one object and the posSlice step - # is performed on all of them (this ensures that _shifted_copies was - # populated and we know the number of layers) - my $n_layers = 0; - if ($self->print->object_step_done(STEP_SLICE)) { - my %z = (); # z => 1 - foreach my $object (@{$self->{print}->objects}) { - foreach my $layer (@{$object->layers}, @{$object->support_layers}) { - $z{$layer->print_z} = 1; - } - } - $self->{layers_z} = [ sort { $a <=> $b } keys %z ]; - $n_layers = scalar(@{$self->{layers_z}}); - } - - if ($n_layers == 0) { - $self->reset_sliders; - Slic3r::GUI::_3DScene::reset_legend_texture(); - $self->canvas->Refresh; # clears canvas - return; - } - - if ($self->{preferred_color_mode} eq 'tool_or_feature') { - # It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature. - # Color by feature if it is a single extruder print. - my $extruders = $self->{print}->extruders; - my $type = (scalar(@{$extruders}) > 1) ? $self->{tool_idx} : 0; - $self->gcode_preview_data->set_type($type); - $self->{choice_view_type}->SetSelection($type); - # If the ->SetSelection changed the following line, revert it to "decide yourself". - $self->{preferred_color_mode} = 'tool_or_feature'; - } - - # Collect colors per extruder. - my @colors = (); - if (! $self->gcode_preview_data->empty() || $self->gcode_preview_data->type == $self->{tool_idx}) { - my @extruder_colors = @{$self->{config}->extruder_colour}; - my @filament_colors = @{$self->{config}->filament_colour}; - for (my $i = 0; $i <= $#extruder_colors; $i += 1) { - my $color = $extruder_colors[$i]; - $color = $filament_colors[$i] if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); - $color = '#FFFFFF' if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); - push @colors, $color; - } - } - if($self->gcode_preview_data->type == $self->{filament_idx}) { - my @extruder_colors = @{$self->{config}->extruder_colour}; - my @filament_colors = @{$self->{config}->filament_colour}; - for (my $i = 0; $i <= $#extruder_colors; $i += 1) { - my $color = $filament_colors[$i]; - $color = '#FFFFFF' if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); - push @colors, $color; - } - } - - if ($self->IsShown) { - # used to set the sliders to the extremes of the current zs range - $self->{force_sliders_full_range} = 0; - - if ($self->gcode_preview_data->empty) { - # load skirt and brim - Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print); - Slic3r::GUI::_3DScene::load_preview($self->canvas, \@colors); - $self->show_hide_ui_elements('simple'); - } else { - $self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0); - Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print); - Slic3r::GUI::_3DScene::load_gcode_preview($self->canvas, $self->gcode_preview_data, \@colors); - $self->show_hide_ui_elements('full'); - - # recalculates zs and update sliders accordingly - $self->{layers_z} = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 1); - $n_layers = scalar(@{$self->{layers_z}}); - if ($n_layers == 0) { - # all layers filtered out - $self->reset_sliders; - $self->canvas->Refresh; # clears canvas - } - } - - $self->update_sliders($n_layers) if ($n_layers > 0); - $self->_loaded(1); - } -} - -sub reset_sliders { - my ($self) = @_; - $self->enabled(0); -# $self->set_z_range(0,0); -# $self->slider_low->Hide; -# $self->slider_high->Hide; -# $self->{z_label_low}->SetLabel(""); -# $self->{z_label_high}->SetLabel(""); -# $self->{z_label_low_idx}->SetLabel(""); -# $self->{z_label_high_idx}->SetLabel(""); - - Slic3r::GUI::reset_double_slider(); - $self->double_slider_sizer->Hide(0); -} - -sub update_sliders -{ - my ($self, $n_layers) = @_; - -# my $z_idx_low = $self->slider_low->GetValue; -# my $z_idx_high = $self->slider_high->GetValue; - $self->enabled(1); -# $self->slider_low->SetRange(0, $n_layers - 1); -# $self->slider_high->SetRange(0, $n_layers - 1); - -# if ($self->{force_sliders_full_range}) { -# $z_idx_low = 0; -# $z_idx_high = $n_layers - 1; -# } elsif ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) { -# # search new indices for nearest z (size of $self->{layers_z} may change in dependence of what is shown) -# if (defined($self->{z_low})) { -# for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) { -# if ($self->{layers_z}[$i] <= $self->{z_low}) { -# $z_idx_low = $i; -# last; -# } -# } -# } -# if (defined($self->{z_high})) { -# for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) { -# if ($self->{layers_z}[$i] <= $self->{z_high}) { -# $z_idx_high = $i; -# last; -# } -# } -# } -# } elsif ($z_idx_high >= $n_layers) { -# # Out of range. Disable 'single layer' view. -# $self->single_layer(0); -# $self->{checkbox_singlelayer}->SetValue(0); -# $z_idx_low = 0; -# $z_idx_high = $n_layers - 1; -# } else { -# $z_idx_low = 0; -# $z_idx_high = $n_layers - 1; -# } - -# $self->slider_low->SetValue($z_idx_low); -# $self->slider_high->SetValue($z_idx_high); -# $self->slider_low->Show; -# $self->slider_high->Show; -# $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]); - - Slic3r::GUI::update_double_slider($self->{force_sliders_full_range}); - $self->double_slider_sizer->Show(0); - - $self->Layout; -} - -sub set_z_range -{ - my ($self, $z_low, $z_high) = @_; - - return if !$self->enabled; - $self->{z_low} = $z_low; - $self->{z_high} = $z_high; - $self->{z_label_low}->SetLabel(sprintf '%.2f', $z_low); - $self->{z_label_high}->SetLabel(sprintf '%.2f', $z_high); - - my $layers_z = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 0); - for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) { - if (($z_low - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_low + 1e-6)) { - $self->{z_label_low_idx}->SetLabel(sprintf '%d', $i + 1); - last; - } - } - for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) { - if (($z_high - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_high + 1e-6)) { - $self->{z_label_high_idx}->SetLabel(sprintf '%d', $i + 1); - last; - } - } - - Slic3r::GUI::_3DScene::set_toolpaths_range($self->canvas, $z_low - 1e-6, $z_high + 1e-6); - $self->canvas->Refresh if $self->IsShown; -} - -sub set_z_idx_low -{ - my ($self, $idx_low) = @_; - if ($self->enabled) { - my $idx_high = $self->slider_high->GetValue; - if ($idx_low >= $idx_high) { - $idx_high = $idx_low; - $self->slider_high->SetValue($idx_high); - } - $self->set_z_range($self->{layers_z}[$idx_low], $self->{layers_z}[$idx_high]); - } -} - -sub set_z_idx_high -{ - my ($self, $idx_high) = @_; - if ($self->enabled) { - my $idx_low = $self->slider_low->GetValue; - if ($idx_low > $idx_high) { - $idx_low = $idx_high; - $self->slider_low->SetValue($idx_low); - } - $self->set_z_range($self->{layers_z}[$idx_low], $self->{layers_z}[$idx_high]); - } -} - -sub set_number_extruders { - my ($self, $number_extruders) = @_; - if ($self->{number_extruders} != $number_extruders) { - $self->{number_extruders} = $number_extruders; - my $type = ($number_extruders > 1) ? - $self->{tool_idx} # color by a tool number - : 0; # color by a feature type - $self->{choice_view_type}->SetSelection($type); - $self->gcode_preview_data->set_type($type); - $self->{preferred_color_mode} = ($type == $self->{tool_idx}) ? 'tool_or_feature' : 'feature'; - } -} - -sub show_hide_ui_elements { - my ($self, $what) = @_; - my $method = ($what eq 'full') ? 'Enable' : 'Disable'; - $self->{$_}->$method for qw(label_show_features combochecklist_features checkbox_travel checkbox_retractions checkbox_unretractions checkbox_shells); - $method = ($what eq 'none') ? 'Disable' : 'Enable'; - $self->{$_}->$method for qw(label_view_type choice_view_type); -} - -# Called by the Platter wxNotebook when this page is activated. -sub OnActivate { -# my ($self) = @_; -# $self->reload_print(1) if ($self->{reload_delayed}); -} - -1; diff --git a/resources/avrdude/avrdude.conf b/resources/avrdude/avrdude.conf deleted file mode 100644 index 7d99c44d3..000000000 --- a/resources/avrdude/avrdude.conf +++ /dev/null @@ -1,14972 +0,0 @@ -# $Id: avrdude.conf.in 1371 2016-02-15 20:15:07Z joerg_wunsch $ -*- text -*- -# -# AVRDUDE Configuration File -# -# This file contains configuration data used by AVRDUDE which describes -# the programming hardware pinouts and also provides part definitions. -# AVRDUDE's "-C" command line option specifies the location of the -# configuration file. The "-c" option names the programmer configuration -# which must match one of the entry's "id" parameter. The "-p" option -# identifies which part AVRDUDE is going to be programming and must match -# one of the parts' "id" parameter. -# -# DO NOT MODIFY THIS FILE. Modifications will be overwritten the next -# time a "make install" is run. For user-specific additions, use the -# "-C +filename" commandline option. -# -# Possible entry formats are: -# -# programmer -# parent # optional parent -# id = [, [, ] ...] ; # are quoted strings -# desc = ; # quoted string -# type = ; # programmer type, quoted string -# # supported programmer types can be listed by "-c ?type" -# connection_type = parallel | serial | usb -# baudrate = ; # baudrate for avr910-programmer -# vcc = [, ... ] ; # pin number(s) -# buff = [, ... ] ; # pin number(s) -# reset = ; # pin number -# sck = ; # pin number -# mosi = ; # pin number -# miso = ; # pin number -# errled = ; # pin number -# rdyled = ; # pin number -# pgmled = ; # pin number -# vfyled = ; # pin number -# usbvid = ; # USB VID (Vendor ID) -# usbpid = [, ...] # USB PID (Product ID) (1) -# usbdev = ; # USB interface or other device info -# usbvendor = ; # USB Vendor Name -# usbproduct = ; # USB Product Name -# usbsn = ; # USB Serial Number -# -# To invert a bit, use = ~ , the spaces are important. -# For a pin list all pins must be inverted. -# A single pin can be specified as usual = ~ , for lists -# specify it as follows = ~ ( [, ... ] ) . -# -# (1) Not all programmer types can process a list of PIDs. -# ; -# -# part -# id = ; # quoted string -# desc = ; # quoted string -# has_jtag = ; # part has JTAG i/f -# has_debugwire = ; # part has debugWire i/f -# has_pdi = ; # part has PDI i/f -# has_tpi = ; # part has TPI i/f -# devicecode = ; # deprecated, use stk500_devcode -# stk500_devcode = ; # numeric -# avr910_devcode = ; # numeric -# signature = ; # signature bytes -# usbpid = ; # DFU USB PID -# chip_erase_delay = ; # micro-seconds -# reset = dedicated | io; -# retry_pulse = reset | sck; -# pgm_enable = ; -# chip_erase = ; -# chip_erase_delay = ; # chip erase delay (us) -# # STK500 parameters (parallel programming IO lines) -# pagel = ; # pin name in hex, i.e., 0xD7 -# bs2 = ; # pin name in hex, i.e., 0xA0 -# serial = ; # can use serial downloading -# parallel = ; # can use par. programming -# # STK500v2 parameters, to be taken from Atmel's XML files -# timeout = ; -# stabdelay = ; -# cmdexedelay = ; -# synchloops = ; -# bytedelay = ; -# pollvalue = ; -# pollindex = ; -# predelay = ; -# postdelay = ; -# pollmethod = ; -# mode = ; -# delay = ; -# blocksize = ; -# readsize = ; -# hvspcmdexedelay = ; -# # STK500v2 HV programming parameters, from XML -# pp_controlstack = , , ...; # PP only -# hvsp_controlstack = , , ...; # HVSP only -# hventerstabdelay = ; -# progmodedelay = ; # PP only -# latchcycles = ; -# togglevtg = ; -# poweroffdelay = ; -# resetdelayms = ; -# resetdelayus = ; -# hvleavestabdelay = ; -# resetdelay = ; -# synchcycles = ; # HVSP only -# chiperasepulsewidth = ; # PP only -# chiperasepolltimeout = ; -# chiperasetime = ; # HVSP only -# programfusepulsewidth = ; # PP only -# programfusepolltimeout = ; -# programlockpulsewidth = ; # PP only -# programlockpolltimeout = ; -# # JTAG ICE mkII parameters, also from XML files -# allowfullpagebitstream = ; -# enablepageprogramming = ; -# idr = ; # IO addr of IDR (OCD) reg. -# rampz = ; # IO addr of RAMPZ reg. -# spmcr = ; # mem addr of SPMC[S]R reg. -# eecr = ; # mem addr of EECR reg. -# # (only when != 0x3c) -# is_at90s1200 = ; # AT90S1200 part -# is_avr32 = ; # AVR32 part -# -# memory -# paged = ; # yes / no -# size = ; # bytes -# page_size = ; # bytes -# num_pages = ; # numeric -# min_write_delay = ; # micro-seconds -# max_write_delay = ; # micro-seconds -# readback_p1 = ; # byte value -# readback_p2 = ; # byte value -# pwroff_after_write = ; # yes / no -# read = ; -# write = ; -# read_lo = ; -# read_hi = ; -# write_lo = ; -# write_hi = ; -# loadpage_lo = ; -# loadpage_hi = ; -# writepage = ; -# ; -# ; -# -# If any of the above parameters are not specified, the default value -# of 0 is used for numerics or the empty string ("") for string -# values. If a required parameter is left empty, AVRDUDE will -# complain. -# -# Parts can also inherit parameters from previously defined parts -# using the following syntax. In this case specified integer and -# string values override parameter values from the parent part. New -# memory definitions are added to the definitions inherited from the -# parent. -# -# part parent # quoted string -# id = ; # quoted string -# -# ; -# -# NOTES: -# * 'devicecode' is the device code used by the STK500 (see codes -# listed below) -# * Not all memory types will implement all instructions. -# * AVR Fuse bits and Lock bits are implemented as a type of memory. -# * Example memory types are: -# "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high -# fuse), "signature", "calibration", "lock" -# * The memory type specified on the avrdude command line must match -# one of the memory types defined for the specified chip. -# * The pwroff_after_write flag causes avrdude to attempt to -# power the device off and back on after an unsuccessful write to -# the affected memory area if VCC programmer pins are defined. If -# VCC pins are not defined for the programmer, a message -# indicating that the device needs a power-cycle is printed out. -# This flag was added to work around a problem with the -# at90s4433/2333's; see the at90s4433 errata at: -# -# http://www.atmel.com/dyn/resources/prod_documents/doc1280.pdf -# -# INSTRUCTION FORMATS -# -# Instruction formats are specified as a comma seperated list of -# string values containing information (bit specifiers) about each -# of the 32 bits of the instruction. Bit specifiers may be one of -# the following formats: -# -# '1' = the bit is always set on input as well as output -# -# '0' = the bit is always clear on input as well as output -# -# 'x' = the bit is ignored on input and output -# -# 'a' = the bit is an address bit, the bit-number matches this bit -# specifier's position within the current instruction byte -# -# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 -# is address bit 12 on input, a0 is address bit 0. -# -# 'i' = the bit is an input data bit -# -# 'o' = the bit is an output data bit -# -# Each instruction must be composed of 32 bit specifiers. The -# instruction specification closely follows the instruction data -# provided in Atmel's data sheets for their parts. -# -# See below for some examples. -# -# -# The following are STK500 part device codes to use for the -# "devicecode" field of the part. These came from Atmel's software -# section avr061.zip which accompanies the application note -# AVR061 available from: -# -# http://www.atmel.com/dyn/resources/prod_documents/doc2525.pdf -# - -#define ATTINY10 0x10 /* the _old_ one that never existed! */ -#define ATTINY11 0x11 -#define ATTINY12 0x12 -#define ATTINY15 0x13 -#define ATTINY13 0x14 - -#define ATTINY22 0x20 -#define ATTINY26 0x21 -#define ATTINY28 0x22 -#define ATTINY2313 0x23 - -#define AT90S1200 0x33 - -#define AT90S2313 0x40 -#define AT90S2323 0x41 -#define AT90S2333 0x42 -#define AT90S2343 0x43 - -#define AT90S4414 0x50 -#define AT90S4433 0x51 -#define AT90S4434 0x52 -#define ATMEGA48 0x59 - -#define AT90S8515 0x60 -#define AT90S8535 0x61 -#define AT90C8534 0x62 -#define ATMEGA8515 0x63 -#define ATMEGA8535 0x64 - -#define ATMEGA8 0x70 -#define ATMEGA88 0x73 -#define ATMEGA168 0x86 - -#define ATMEGA161 0x80 -#define ATMEGA163 0x81 -#define ATMEGA16 0x82 -#define ATMEGA162 0x83 -#define ATMEGA169 0x84 - -#define ATMEGA323 0x90 -#define ATMEGA32 0x91 - -#define ATMEGA64 0xA0 - -#define ATMEGA103 0xB1 -#define ATMEGA128 0xB2 -#define AT90CAN128 0xB3 -#define AT90CAN64 0xB3 -#define AT90CAN32 0xB3 - -#define AT86RF401 0xD0 - -#define AT89START 0xE0 -#define AT89S51 0xE0 -#define AT89S52 0xE1 - -# The following table lists the devices in the original AVR910 -# appnote: -# |Device |Signature | Code | -# +-------+----------+------+ -# |tiny12 | 1E 90 05 | 0x55 | -# |tiny15 | 1E 90 06 | 0x56 | -# | | | | -# | S1200 | 1E 90 01 | 0x13 | -# | | | | -# | S2313 | 1E 91 01 | 0x20 | -# | S2323 | 1E 91 02 | 0x48 | -# | S2333 | 1E 91 05 | 0x34 | -# | S2343 | 1E 91 03 | 0x4C | -# | | | | -# | S4414 | 1E 92 01 | 0x28 | -# | S4433 | 1E 92 03 | 0x30 | -# | S4434 | 1E 92 02 | 0x6C | -# | | | | -# | S8515 | 1E 93 01 | 0x38 | -# | S8535 | 1E 93 03 | 0x68 | -# | | | | -# |mega32 | 1E 95 01 | 0x72 | -# |mega83 | 1E 93 05 | 0x65 | -# |mega103| 1E 97 01 | 0x41 | -# |mega161| 1E 94 01 | 0x60 | -# |mega163| 1E 94 02 | 0x64 | - -# Appnote AVR109 also has a table of AVR910 device codes, which -# lists: -# dev avr910 signature -# ATmega8 0x77 0x1E 0x93 0x07 -# ATmega8515 0x3B 0x1E 0x93 0x06 -# ATmega8535 0x6A 0x1E 0x93 0x08 -# ATmega16 0x75 0x1E 0x94 0x03 -# ATmega162 0x63 0x1E 0x94 0x04 -# ATmega163 0x66 0x1E 0x94 0x02 -# ATmega169 0x79 0x1E 0x94 0x05 -# ATmega32 0x7F 0x1E 0x95 0x02 -# ATmega323 0x73 0x1E 0x95 0x01 -# ATmega64 0x46 0x1E 0x96 0x02 -# ATmega128 0x44 0x1E 0x97 0x02 -# -# These codes refer to "BOOT" device codes which are apparently -# different than standard device codes, for whatever reasons -# (often one above the standard code). - -# There are several extended versions of AVR910 implementations around -# in the Internet. These add the following codes (only devices that -# actually exist are listed): - -# ATmega8515 0x3A -# ATmega128 0x43 -# ATmega64 0x45 -# ATtiny26 0x5E -# ATmega8535 0x69 -# ATmega32 0x72 -# ATmega16 0x74 -# ATmega8 0x76 -# ATmega169 0x78 - -# -# Overall avrdude defaults; suitable for ~/.avrduderc -# -default_parallel = "/dev/parport0"; -default_serial = "/dev/ttyS0"; -# default_bitclock = 2.5; - -# Turn off safemode by default -#default_safemode = no; - - -# -# PROGRAMMER DEFINITIONS -# - -# http://wiring.org.co/ -# Basically STK500v2 protocol, with some glue to trigger the -# bootloader. -programmer - id = "wiring"; - desc = "Wiring"; - type = "wiring"; - connection_type = serial; -; - -programmer - id = "arduino"; - desc = "Arduino"; - type = "arduino"; - connection_type = serial; -; -# this will interface with the chips on these programmers: -# -# http://real.kiev.ua/old/avreal/en/adapters -# http://www.amontec.com/jtagkey.shtml, jtagkey-tiny.shtml -# http://www.olimex.com/dev/arm-usb-ocd.html, arm-usb-tiny.html -# http://www.ethernut.de/en/hardware/turtelizer/index.html -# http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.html -# http://dangerousprototypes.com/docs/FT2232_breakout_board -# http://www.ftdichip.com/Products/Modules/DLPModules.htm,DLP-2232*,DLP-USB1232H -# http://flashrom.org/FT2232SPI_Programmer -# -# The drivers will look for a specific device and use the first one found. -# If you have mulitple devices, then look for unique information (like SN) -# And fill that in here. -# -# Note that the pin numbers for the main ISP signals (reset, sck, -# mosi, miso) are fixed and cannot be changed, since they must match -# the way the Multi-Protocol Synchronous Serial Engine (MPSSE) of -# these FTDI ICs has been designed. - -# programmer -# id = "avrftdi"; -# desc = "FT2232D based generic programmer"; -# type = "avrftdi"; -# connection_type = usb; -# usbvid = 0x0403; -# usbpid = 0x6010; -# usbvendor = ""; -# usbproduct = ""; -# usbdev = "A"; -# usbsn = ""; -# #ISP-signals - lower ADBUS-Nibble (default) -# reset = 3; -# sck = 0; -# mosi = 1; -# miso = 2; -# #LED SIGNALs - higher ADBUS-Nibble -# # errled = 4; -# # rdyled = 5; -# # pgmled = 6; -# # vfyled = 7; -# #Buffer Signal - ACBUS - Nibble -# # buff = 8; -# ; -# This is an implementation of the above with a buffer IC (74AC244) and -# 4 LEDs directly attached, all active low. -# programmer -# id = "2232HIO"; -# desc = "FT2232H based generic programmer"; -# type = "avrftdi"; -# connection_type = usb; -# usbvid = 0x0403; -# # Note: This PID is reserved for generic H devices and -# # should be programmed into the EEPROM -# # usbpid = 0x8A48; -# usbpid = 0x6010; -# usbdev = "A"; -# usbvendor = ""; -# usbproduct = ""; -# usbsn = ""; -# #ISP-signals -# reset = 3; -# sck = 0; -# mosi = 1; -# miso = 2; -# buff = ~4; -# #LED SIGNALs -# errled = ~ 11; -# rdyled = ~ 14; -# pgmled = ~ 13; -# vfyled = ~ 12; -# ; - -# #The FT4232H can be treated as FT2232H, but it has a different USB -# #device ID of 0x6011. -# programmer parent "avrftdi" -# id = "4232h"; -# desc = "FT4232H based generic programmer"; -# usbpid = 0x6011; -# ; - -# programmer -# id = "jtagkey"; -# desc = "Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2"; -# type = "avrftdi"; -# connection_type = usb; -# usbvid = 0x0403; -# # Note: This PID is used in all JTAGKey variants -# usbpid = 0xCFF8; -# usbdev = "A"; -# usbvendor = ""; -# usbproduct = ""; -# usbsn = ""; -# #ISP-signals => 20 - Pin connector on JTAGKey -# reset = 3; # TMS 7 violet -# sck = 0; # TCK 9 white -# mosi = 1; # TDI 5 green -# miso = 2; # TDO 13 orange -# buff = ~4; -# # VTG VREF 1 brown with red tip -# # GND GND 20 black -# # The colors are on the 20 pin breakout cable -# # from Amontec -# ; - -# # UM232H module from FTDI and Glyn.com.au. -# # See helix.air.net.au for detailed usage information. -# # J1: Connect pin 2 and 3 for USB power. -# # J2: Connect pin 2 and 3 for USB power. -# # J2: Pin 7 is SCK -# # : Pin 8 is MOSI -# # : Pin 9 is MISO -# # : Pin 11 is RST -# # : Pin 6 is ground -# # Use the -b flag to set the SPI clock rate eg -b 3750000 is the fastest I could get -# # a 16MHz Atmega1280 to program reliably. The 232H is conveniently 5V tolerant. -# programmer -# id = "UM232H"; -# desc = "FT232H based module from FTDI and Glyn.com.au"; -# type = "avrftdi"; -# usbvid = 0x0403; -# # Note: This PID is reserved for generic 232H devices and -# # should be programmed into the EEPROM -# usbpid = 0x6014; -# usbdev = "A"; -# usbvendor = ""; -# usbproduct = ""; -# usbsn = ""; -# #ISP-signals -# sck = 0; -# mosi = 1; -# miso = 2; -# reset = 3; -# ; - -# # C232HM module from FTDI and Glyn.com.au. -# # : Orange is SCK -# # : Yellow is MOSI -# # : Green is MISO -# # : Brown is RST -# # : Black is ground -# # Use the -b flag to set the SPI clock rate eg -b 3750000 is the fastest I could get -# # a 16MHz Atmega1280 to program reliably. The 232H is conveniently 5V tolerant. -# programmer -# id = "C232HM"; -# desc = "FT232H based module from FTDI and Glyn.com.au"; -# type = "avrftdi"; -# usbvid = 0x0403; -# # Note: This PID is reserved for generic 232H devices and -# # should be programmed into the EEPROM -# usbpid = 0x6014; -# usbdev = "A"; -# usbvendor = ""; -# usbproduct = ""; -# usbsn = ""; -# #ISP-signals -# sck = 0; -# mosi = 1; -# miso = 2; -# reset = 3; -# ; - - -# # On the adapter you can read "O-Link". On the PCB is printed "OpenJTAG v3.1" -# # You can find it as "OpenJTAG ARM JTAG USB" in the internet. -# # (But there are also several projects called Open JTAG, eg. -# # http://www.openjtag.org, which are completely different.) -# # http://www.100ask.net/shop/english.html (website seems to be outdated) -# # http://item.taobao.com/item.htm?id=1559277013 -# # http://www.micro4you.com/store/openjtag-arm-jtag-usb.html (schematics!) -# # some other sources which call it O-Link -# # http://www.andahammer.com/olink/ -# # http://www.developmentboard.net/31-o-link-debugger.html -# # http://armwerks.com/catalog/o-link-debugger-copy/ -# # or just have a look at ebay ... -# # It is basically the same entry as jtagkey with different usb ids. -# programmer parent "jtagkey" -# id = "o-link"; -# desc = "O-Link, OpenJTAG from www.100ask.net"; -# usbvid = 0x1457; -# usbpid = 0x5118; -# usbvendor = "www.100ask.net"; -# usbproduct = "USB<=>JTAG&RS232"; -# ; - -# # http://wiki.openmoko.org/wiki/Debug_Board_v3 -# programmer -# id = "openmoko"; -# desc = "Openmoko debug board (v3)"; -# type = "avrftdi"; -# usbvid = 0x1457; -# usbpid = 0x5118; -# usbdev = "A"; -# usbvendor = ""; -# usbproduct = ""; -# usbsn = ""; -# reset = 3; # TMS 7 -# sck = 0; # TCK 9 -# mosi = 1; # TDI 5 -# miso = 2; # TDO 13 -# ; - -# # Only Rev. A boards. -# # Schematic and user manual: http://www.cs.put.poznan.pl/wswitala/download/pdf/811EVBK.pdf -# programmer -# id = "lm3s811"; -# desc = "Luminary Micro LM3S811 Eval Board (Rev. A)"; -# type = "avrftdi"; -# connection_type = usb; -# usbvid = 0x0403; -# usbpid = 0xbcd9; -# usbvendor = "LMI"; -# usbproduct = "LM3S811 Evaluation Board"; -# usbdev = "A"; -# usbsn = ""; -# #ISP-signals - lower ACBUS-Nibble (default) -# reset = 3; -# sck = 0; -# mosi = 1; -# miso = 2; -# # Enable correct buffers -# buff = 7; -# ; - -# # submitted as bug #46020 -# programmer -# id = "tumpa"; -# desc = "TIAO USB Multi-Protocol Adapter"; -# type = "avrftdi"; -# connection_type = usb; -# usbvid = 0x0403; -# usbpid = 0x8A98; -# usbdev = "A"; -# usbvendor = "TIAO"; -# usbproduct = ""; -# usbsn = ""; -# sck = 0; # TCK 9 -# mosi = 1; # TDI 5 -# miso = 2; # TDO 13 -# reset = 3; # TMS 7 -# ; - -programmer - id = "avrisp"; - desc = "Atmel AVR ISP"; - type = "stk500"; - connection_type = serial; -; - -programmer - id = "avrispv2"; - desc = "Atmel AVR ISP V2"; - type = "stk500v2"; - connection_type = serial; -; - -# programmer -# id = "avrispmkII"; -# desc = "Atmel AVR ISP mkII"; -# type = "stk500v2"; -# connection_type = usb; -# ; - -# programmer parent "avrispmkII" -# id = "avrisp2"; -# ; - -programmer - id = "buspirate"; - desc = "The Bus Pirate"; - type = "buspirate"; - connection_type = serial; -; - -programmer - id = "buspirate_bb"; - desc = "The Bus Pirate (bitbang interface, supports TPI)"; - type = "buspirate_bb"; - connection_type = serial; - # pins are bits in bitbang byte (numbers are 87654321) - # 1|POWER|PULLUP|AUX|MOSI|CLK|MISO|CS - reset = 1; - sck = 3; - mosi = 4; - miso = 2; - #vcc = 7; This is internally set independent of this setting. -; - -# This is supposed to be the "default" STK500 entry. -# Attempts to select the correct firmware version -# by probing for it. Better use one of the entries -# below instead. -programmer - id = "stk500"; - desc = "Atmel STK500"; - type = "stk500generic"; - connection_type = serial; -; - -programmer - id = "stk500v1"; - desc = "Atmel STK500 Version 1.x firmware"; - type = "stk500"; - connection_type = serial; -; - -programmer - id = "mib510"; - desc = "Crossbow MIB510 programming board"; - type = "stk500"; - connection_type = serial; -; - -programmer - id = "stk500v2"; - desc = "Atmel STK500 Version 2.x firmware"; - type = "stk500v2"; - connection_type = serial; -; - -programmer - id = "stk500pp"; - desc = "Atmel STK500 V2 in parallel programming mode"; - type = "stk500pp"; - connection_type = serial; -; - -programmer - id = "stk500hvsp"; - desc = "Atmel STK500 V2 in high-voltage serial programming mode"; - type = "stk500hvsp"; - connection_type = serial; -; - -# programmer -# id = "stk600"; -# desc = "Atmel STK600"; -# type = "stk600"; -# connection_type = usb; -# ; - -# programmer -# id = "stk600pp"; -# desc = "Atmel STK600 in parallel programming mode"; -# type = "stk600pp"; -# connection_type = usb; -# ; - -# programmer -# id = "stk600hvsp"; -# desc = "Atmel STK600 in high-voltage serial programming mode"; -# type = "stk600hvsp"; -# connection_type = usb; -# ; - -programmer - id = "avr910"; - desc = "Atmel Low Cost Serial Programmer"; - type = "avr910"; - connection_type = serial; -; - -# programmer -# id = "ft245r"; -# desc = "FT245R Synchronous BitBang"; -# type = "ftdi_syncbb"; -# connection_type = usb; -# miso = 1; # D1 -# sck = 0; # D0 -# mosi = 2; # D2 -# reset = 4; # D4 -# ; - -# programmer -# id = "ft232r"; -# desc = "FT232R Synchronous BitBang"; -# type = "ftdi_syncbb"; -# connection_type = usb; -# miso = 1; # RxD -# sck = 0; # TxD -# mosi = 2; # RTS -# reset = 4; # DTR -# ; - -# # see http://www.bitwizard.nl/wiki/index.php/FTDI_ATmega -# programmer -# id = "bwmega"; -# desc = "BitWizard ftdi_atmega builtin programmer"; -# type = "ftdi_syncbb"; -# connection_type = usb; -# miso = 5; # DSR -# sck = 6; # DCD -# mosi = 3; # CTS -# reset = 7; # RI -# ; - -# # see http://www.geocities.jp/arduino_diecimila/bootloader/index_en.html -# # Note: pins are numbered from 1! -# programmer -# id = "arduino-ft232r"; -# desc = "Arduino: FT232R connected to ISP"; -# type = "ftdi_syncbb"; -# connection_type = usb; -# miso = 3; # CTS X3(1) -# sck = 5; # DSR X3(2) -# mosi = 6; # DCD X3(3) -# reset = 7; # RI X3(4) -# ; - -# # website mentioned above uses this id -# programmer parent "arduino-ft232r" -# id = "diecimila"; -# desc = "alias for arduino-ft232r"; -# ; - -# # There is a ATmega328P kit PCB called "uncompatino". -# # This board allows ISP via its on-board FT232R. -# # This is designed like Arduino Duemilanove but has no standard ICPS header. -# # Its 4 pairs of pins are shorted to enable ftdi_syncbb. -# # http://akizukidenshi.com/catalog/g/gP-07487/ -# # http://akizukidenshi.com/download/ds/akizuki/k6096_manual_20130816.pdf -# programmer -# id = "uncompatino"; -# desc = "uncompatino with all pairs of pins shorted"; -# type = "ftdi_syncbb"; -# connection_type = usb; -# miso = 3; # cts -# sck = 5; # dsr -# mosi = 6; # dcd -# reset = 7; # ri -# ; - -# # FTDI USB to serial cable TTL-232R-5V with a custom adapter for ICSP -# # http://www.ftdichip.com/Products/Cables/USBTTLSerial.htm -# # http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf -# # For ICSP pinout see for example http://www.atmel.com/images/doc2562.pdf -# # (Figure 1. ISP6PIN header pinout and Table 1. Connections required for ISP ...) -# # TTL-232R GND 1 Black -> ICPS GND (pin 6) -# # TTL-232R CTS 2 Brown -> ICPS MOSI (pin 4) -# # TTL-232R VCC 3 Red -> ICPS VCC (pin 2) -# # TTL-232R TXD 4 Orange -> ICPS RESET (pin 5) -# # TTL-232R RXD 5 Yellow -> ICPS SCK (pin 3) -# # TTL-232R RTS 6 Green -> ICPS MISO (pin 1) -# # Except for VCC and GND, you can connect arbitual pairs as long as -# # the following table is adjusted. -# programmer -# id = "ttl232r"; -# desc = "FTDI TTL232R-5V with ICSP adapter"; -# type = "ftdi_syncbb"; -# connection_type = usb; -# miso = 2; # rts -# sck = 1; # rxd -# mosi = 3; # cts -# reset = 0; # txd -# ; - -# programmer -# id = "usbasp"; -# desc = "USBasp, http://www.fischl.de/usbasp/"; -# type = "usbasp"; -# connection_type = usb; -# usbvid = 0x16C0; # VOTI -# usbpid = 0x05DC; # Obdev's free shared PID -# usbvendor = "www.fischl.de"; -# usbproduct = "USBasp"; - -# # following variants are autodetected for id "usbasp" - -# # original usbasp from fischl.de -# # see above "usbasp" - -# # old usbasp from fischl.de -# #usbvid = 0x03EB; # ATMEL -# #usbpid = 0xC7B4; # (unoffical) USBasp -# #usbvendor = "www.fischl.de"; -# #usbproduct = "USBasp"; - -# # NIBObee (only if -P nibobee is given on command line) -# # see below "nibobee" -# ; - -# programmer -# id = "nibobee"; -# desc = "NIBObee"; -# type = "usbasp"; -# connection_type = usb; -# usbvid = 0x16C0; # VOTI -# usbpid = 0x092F; # NIBObee PID -# usbvendor = "www.nicai-systems.com"; -# usbproduct = "NIBObee"; -# ; - -# programmer -# id = "usbasp-clone"; -# desc = "Any usbasp clone with correct VID/PID"; -# type = "usbasp"; -# connection_type = usb; -# usbvid = 0x16C0; # VOTI -# usbpid = 0x05DC; # Obdev's free shared PID -# #usbvendor = ""; -# #usbproduct = ""; -# ; - -# programmer -# id = "usbtiny"; -# desc = "USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/"; -# type = "usbtiny"; -# connection_type = usb; -# usbvid = 0x1781; -# usbpid = 0x0c9f; -# ; - -programmer - id = "butterfly"; - desc = "Atmel Butterfly Development Board"; - type = "butterfly"; - connection_type = serial; -; - -programmer - id = "avr109"; - desc = "Atmel AppNote AVR109 Boot Loader"; - type = "butterfly"; - connection_type = serial; -; - -programmer - id = "avr911"; - desc = "Atmel AppNote AVR911 AVROSP"; - type = "butterfly"; - connection_type = serial; -; - -# suggested in http://forum.mikrokopter.de/topic-post48317.html -programmer - id = "mkbutterfly"; - desc = "Mikrokopter.de Butterfly"; - type = "butterfly_mk"; - connection_type = serial; -; - -programmer parent "mkbutterfly" - id = "butterfly_mk"; -; - -# programmer -# id = "jtagmkI"; -# desc = "Atmel JTAG ICE (mkI)"; -# baudrate = 115200; # default is 115200 -# type = "jtagmki"; -# connection_type = serial; -# ; - -# # easier to type -# programmer parent "jtagmkI" -# id = "jtag1"; -# ; - -# # easier to type -# programmer parent "jtag1" -# id = "jtag1slow"; -# baudrate = 19200; -# ; - -# # The JTAG ICE mkII has both, serial and USB connectivity. As it is -# # mostly used through USB these days (AVR Studio 5 only supporting it -# # that way), we make connection_type = usb the default. Users are -# # still free to use a serial port with the -P option. - -# programmer -# id = "jtagmkII"; -# desc = "Atmel JTAG ICE mkII"; -# baudrate = 19200; # default is 19200 -# type = "jtagmkii"; -# connection_type = usb; -# ; - -# # easier to type -# programmer parent "jtagmkII" -# id = "jtag2slow"; -# ; - -# # JTAG ICE mkII @ 115200 Bd -# programmer parent "jtag2slow" -# id = "jtag2fast"; -# baudrate = 115200; -# ; - -# # make the fast one the default, people will love that -# programmer parent "jtag2fast" -# id = "jtag2"; -# ; - -# # JTAG ICE mkII in ISP mode -# programmer -# id = "jtag2isp"; -# desc = "Atmel JTAG ICE mkII in ISP mode"; -# baudrate = 115200; -# type = "jtagmkii_isp"; -# connection_type = usb; -# ; - -# # JTAG ICE mkII in debugWire mode -# programmer -# id = "jtag2dw"; -# desc = "Atmel JTAG ICE mkII in debugWire mode"; -# baudrate = 115200; -# type = "jtagmkii_dw"; -# connection_type = usb; -# ; - -# # JTAG ICE mkII in AVR32 mode -# programmer -# id = "jtagmkII_avr32"; -# desc = "Atmel JTAG ICE mkII im AVR32 mode"; -# baudrate = 115200; -# type = "jtagmkii_avr32"; -# connection_type = usb; -# ; - -# # JTAG ICE mkII in AVR32 mode -# programmer -# id = "jtag2avr32"; -# desc = "Atmel JTAG ICE mkII im AVR32 mode"; -# baudrate = 115200; -# type = "jtagmkii_avr32"; -# connection_type = usb; -# ; - -# # JTAG ICE mkII in PDI mode -# programmer -# id = "jtag2pdi"; -# desc = "Atmel JTAG ICE mkII PDI mode"; -# baudrate = 115200; -# type = "jtagmkii_pdi"; -# connection_type = usb; -# ; - -# # AVR Dragon in JTAG mode -# programmer -# id = "dragon_jtag"; -# desc = "Atmel AVR Dragon in JTAG mode"; -# baudrate = 115200; -# type = "dragon_jtag"; -# connection_type = usb; -# ; - -# # AVR Dragon in ISP mode -# programmer -# id = "dragon_isp"; -# desc = "Atmel AVR Dragon in ISP mode"; -# baudrate = 115200; -# type = "dragon_isp"; -# connection_type = usb; -# ; - -# # AVR Dragon in PP mode -# programmer -# id = "dragon_pp"; -# desc = "Atmel AVR Dragon in PP mode"; -# baudrate = 115200; -# type = "dragon_pp"; -# connection_type = usb; -# ; - -# # AVR Dragon in HVSP mode -# programmer -# id = "dragon_hvsp"; -# desc = "Atmel AVR Dragon in HVSP mode"; -# baudrate = 115200; -# type = "dragon_hvsp"; -# connection_type = usb; -# ; - -# # AVR Dragon in debugWire mode -# programmer -# id = "dragon_dw"; -# desc = "Atmel AVR Dragon in debugWire mode"; -# baudrate = 115200; -# type = "dragon_dw"; -# connection_type = usb; -# ; - -# # AVR Dragon in PDI mode -# programmer -# id = "dragon_pdi"; -# desc = "Atmel AVR Dragon in PDI mode"; -# baudrate = 115200; -# type = "dragon_pdi"; -# connection_type = usb; -# ; - -# programmer -# id = "jtag3"; -# desc = "Atmel AVR JTAGICE3 in JTAG mode"; -# type = "jtagice3"; -# connection_type = usb; -# usbpid = 0x2110, 0x2140; -# ; - -# programmer -# id = "jtag3pdi"; -# desc = "Atmel AVR JTAGICE3 in PDI mode"; -# type = "jtagice3_pdi"; -# connection_type = usb; -# usbpid = 0x2110, 0x2140; -# ; - -# programmer -# id = "jtag3dw"; -# desc = "Atmel AVR JTAGICE3 in debugWIRE mode"; -# type = "jtagice3_dw"; -# connection_type = usb; -# usbpid = 0x2110, 0x2140; -# ; - -# programmer -# id = "jtag3isp"; -# desc = "Atmel AVR JTAGICE3 in ISP mode"; -# type = "jtagice3_isp"; -# connection_type = usb; -# usbpid = 0x2110, 0x2140; -# ; - -# programmer -# id = "xplainedpro"; -# desc = "Atmel AVR XplainedPro in JTAG mode"; -# type = "jtagice3"; -# connection_type = usb; -# usbpid = 0x2111; -# ; - -# programmer -# id = "xplainedmini"; -# desc = "Atmel AVR XplainedMini in ISP mode"; -# type = "jtagice3_isp"; -# connection_type = usb; -# usbpid = 0x2145; -# ; - -# programmer -# id = "xplainedmini_dw"; -# desc = "Atmel AVR XplainedMini in debugWIRE mode"; -# type = "jtagice3_dw"; -# connection_type = usb; -# usbpid = 0x2145; -# ; - -# programmer -# id = "atmelice"; -# desc = "Atmel-ICE (ARM/AVR) in JTAG mode"; -# type = "jtagice3"; -# connection_type = usb; -# usbpid = 0x2141; -# ; - -# programmer -# id = "atmelice_pdi"; -# desc = "Atmel-ICE (ARM/AVR) in PDI mode"; -# type = "jtagice3_pdi"; -# connection_type = usb; -# usbpid = 0x2141; -# ; - -# programmer -# id = "atmelice_dw"; -# desc = "Atmel-ICE (ARM/AVR) in debugWIRE mode"; -# type = "jtagice3_dw"; -# connection_type = usb; -# usbpid = 0x2141; -# ; - -# programmer -# id = "atmelice_isp"; -# desc = "Atmel-ICE (ARM/AVR) in ISP mode"; -# type = "jtagice3_isp"; -# connection_type = usb; -# usbpid = 0x2141; -# ; - - -programmer - id = "pavr"; - desc = "Jason Kyle's pAVR Serial Programmer"; - type = "avr910"; - connection_type = serial; -; - -# programmer -# id = "pickit2"; -# desc = "MicroChip's PICkit2 Programmer"; -# type = "pickit2"; -# connection_type = usb; -# ; - -# programmer -# id = "flip1"; -# desc = "FLIP USB DFU protocol version 1 (doc7618)"; -# type = "flip1"; -# connection_type = usb; -# ; - -# programmer -# id = "flip2"; -# desc = "FLIP USB DFU protocol version 2 (AVR4023)"; -# type = "flip2"; -# connection_type = usb; -# ; - -# Parallel port programmers. - -# programmer -# id = "bsd"; -# desc = "Brian Dean's Programmer, http://www.bsdhome.com/avrdude/"; -# type = "par"; -# connection_type = parallel; -# vcc = 2, 3, 4, 5; -# reset = 7; -# sck = 8; -# mosi = 9; -# miso = 10; -# ; - -# programmer -# id = "stk200"; -# desc = "STK200"; -# type = "par"; -# connection_type = parallel; -# buff = 4, 5; -# sck = 6; -# mosi = 7; -# reset = 9; -# miso = 10; -# ; - -# The programming dongle used by the popular Ponyprog -# utility. It is almost similar to the STK200 one, -# except that there is a LED indicating that the -# programming is currently in progress. - -# programmer parent "stk200" -# id = "pony-stk200"; -# desc = "Pony Prog STK200"; -# pgmled = 8; -# ; - -# programmer -# id = "dt006"; -# desc = "Dontronics DT006"; -# type = "par"; -# connection_type = parallel; -# reset = 4; -# sck = 5; -# mosi = 2; -# miso = 11; -# ; - -# programmer parent "dt006" -# id = "bascom"; -# desc = "Bascom SAMPLE programming cable"; -# ; - -# programmer -# id = "alf"; -# desc = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/"; -# type = "par"; -# connection_type = parallel; -# vcc = 2, 3, 4, 5; -# buff = 6; -# reset = 7; -# sck = 8; -# mosi = 9; -# miso = 10; -# errled = 1; -# rdyled = 14; -# pgmled = 16; -# vfyled = 17; -# ; - -# programmer -# id = "sp12"; -# desc = "Steve Bolt's Programmer"; -# type = "par"; -# connection_type = parallel; -# vcc = 4,5,6,7,8; -# reset = 3; -# sck = 2; -# mosi = 9; -# miso = 11; -# ; - -# programmer -# id = "picoweb"; -# desc = "Picoweb Programming Cable, http://www.picoweb.net/"; -# type = "par"; -# connection_type = parallel; -# reset = 2; -# sck = 3; -# mosi = 4; -# miso = 13; -# ; - -# programmer -# id = "abcmini"; -# desc = "ABCmini Board, aka Dick Smith HOTCHIP"; -# type = "par"; -# connection_type = parallel; -# reset = 4; -# sck = 3; -# mosi = 2; -# miso = 10; -# ; - -# programmer -# id = "futurlec"; -# desc = "Futurlec.com programming cable."; -# type = "par"; -# connection_type = parallel; -# reset = 3; -# sck = 2; -# mosi = 1; -# miso = 10; -# ; - - -# From the contributor of the "xil" jtag cable: -# The "vcc" definition isn't really vcc (the cable gets its power from -# the programming circuit) but is necessary to switch one of the -# buffer lines (trying to add it to the "buff" lines doesn't work in -# avrdude versions before 5.5j). -# With this, TMS connects to RESET, TDI to MOSI, TDO to MISO and TCK -# to SCK (plus vcc/gnd of course) -# programmer -# id = "xil"; -# desc = "Xilinx JTAG cable"; -# type = "par"; -# connection_type = parallel; -# mosi = 2; -# sck = 3; -# reset = 4; -# buff = 5; -# miso = 13; -# vcc = 6; -# ; - - -# programmer -# id = "dapa"; -# desc = "Direct AVR Parallel Access cable"; -# type = "par"; -# connection_type = parallel; -# vcc = 3; -# reset = 16; -# sck = 1; -# mosi = 2; -# miso = 11; -# ; - -# programmer -# id = "atisp"; -# desc = "AT-ISP V1.1 programming cable for AVR-SDK1 from micro-research.co.th"; -# type = "par"; -# connection_type = parallel; -# reset = ~6; -# sck = ~8; -# mosi = ~7; -# miso = ~10; -# ; - -# programmer -# id = "ere-isp-avr"; -# desc = "ERE ISP-AVR "; -# type = "par"; -# connection_type = parallel; -# reset = ~4; -# sck = 3; -# mosi = 2; -# miso = 10; -# ; - -# programmer -# id = "blaster"; -# desc = "Altera ByteBlaster"; -# type = "par"; -# connection_type = parallel; -# sck = 2; -# miso = 11; -# reset = 3; -# mosi = 8; -# buff = 14; -# ; - -# It is almost same as pony-stk200, except vcc on pin 5 to auto -# disconnect port (download on http://electropol.free.fr/spip/spip.php?article27) -# programmer parent "pony-stk200" -# id = "frank-stk200"; -# desc = "Frank STK200"; -# buff = ; # delete buff pin assignment -# vcc = 5; -# ; - -# The AT98ISP Cable is a simple parallel dongle for AT89 family. -# http://www.atmel.com/dyn/products/tools_card.asp?tool_id=2877 -# programmer -# id = "89isp"; -# desc = "Atmel at89isp cable"; -# type = "par"; -# connection_type = parallel; -# reset = 17; -# sck = 1; -# mosi = 2; -# miso = 10; -# ; - - -#This programmer bitbangs GPIO lines using the Linux sysfs GPIO interface -# -#To enable it set the configuration below to match the GPIO lines connected to the -#relevant ISP header pins and uncomment the entry definition. In case you don't -#have the required permissions to edit this system wide config file put the -#entry in a separate .conf file and use it with -C+.conf -#on the command line. -# -#To check if your avrdude build has support for the linuxgpio programmer compiled in, -#use -c?type on the command line and look for linuxgpio in the list. If it's not available -#you need pass the --enable-linuxgpio=yes option to configure and recompile avrdude. -# -#programmer -# id = "linuxgpio"; -# desc = "Use the Linux sysfs interface to bitbang GPIO lines"; -# type = "linuxgpio"; -# reset = ?; -# sck = ?; -# mosi = ?; -# miso = ?; -#; - -# some ultra cheap programmers use bitbanging on the -# serialport. -# -# PC - DB9 - Pins for RS232: -# -# GND 5 -- |O -# | O| <- 9 RI -# DTR 4 <- |O | -# | O| <- 8 CTS -# TXD 3 <- |O | -# | O| -> 7 RTS -# RXD 2 -> |O | -# | O| <- 6 DSR -# DCD 1 -> |O -# -# Using RXD is currently not supported. -# Using RI is not supported under Win32 but is supported under Posix. - -# serial ponyprog design (dasa2 in uisp) -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "ponyser"; - desc = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts"; - type = "serbb"; - connection_type = serial; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# Same as above, different name -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer parent "ponyser" - id = "siprog"; - desc = "Lancos SI-Prog "; -; - -# unknown (dasa in uisp) -# reset=rts sck=dtr mosi=txd miso=cts - -programmer - id = "dasa"; - desc = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts"; - type = "serbb"; - connection_type = serial; - reset = 7; - sck = 4; - mosi = 3; - miso = 8; -; - -# unknown (dasa3 in uisp) -# reset=!dtr sck=rts mosi=txd miso=cts - -programmer - id = "dasa3"; - desc = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts"; - type = "serbb"; - connection_type = serial; - reset = ~4; - sck = 7; - mosi = 3; - miso = 8; -; - -# C2N232i (jumper configuration "auto") -# reset=dtr sck=!rts mosi=!txd miso=!cts - -programmer - id = "c2n232i"; - desc = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts"; - type = "serbb"; - connection_type = serial; - reset = 4; - sck = ~7; - mosi = ~3; - miso = ~8; -; - -# -# PART DEFINITIONS -# - -#------------------------------------------------------------ -# ATtiny11 -#------------------------------------------------------------ - -# This is an HVSP-only device. - -part - id = "t11"; - desc = "ATtiny11"; - stk500_devcode = 0x11; - signature = 0x1e 0x90 0x04; - chip_erase_delay = 20000; - - timeout = 200; - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - blocksize = 64; - readsize = 256; - delay = 5; - ; - - memory "flash" - size = 1024; - blocksize = 128; - readsize = 256; - delay = 3; - ; - - memory "signature" - size = 3; - ; - - memory "lock" - size = 1; - ; - - memory "calibration" - size = 1; - ; - - memory "fuse" - size = 1; - ; -; - -#------------------------------------------------------------ -# ATtiny12 -#------------------------------------------------------------ - -part - id = "t12"; - desc = "ATtiny12"; - stk500_devcode = 0x12; - avr910_devcode = 0x55; - signature = 0x1e 0x90 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 8; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4500; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# ATtiny13 -#------------------------------------------------------------ - -part - id = "t13"; - desc = "ATtiny13"; - has_debugwire = yes; - flash_instr = 0xB4, 0x0E, 0x1E; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x0E, 0xB4, 0x0E, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; - signature = 0x1e 0x90 0x07; - chip_erase_delay = 4000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 90; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 0; - - memory "eeprom" - size = 64; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 1024; - page_size = 32; - num_pages = 32; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny15 -#------------------------------------------------------------ - -part - id = "t15"; - desc = "ATtiny15"; - stk500_devcode = 0x13; - avr910_devcode = 0x56; - signature = 0x1e 0x90 0x06; - chip_erase_delay = 8200; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 5; - synchcycles = 6; - latchcycles = 16; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 8200; - max_write_delay = 8200; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4100; - max_write_delay = 4100; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o x x o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i 1 1 i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# AT90s1200 -#------------------------------------------------------------ - -part - id = "1200"; - desc = "AT90S1200"; - is_at90s1200 = yes; - stk500_devcode = 0x33; - avr910_devcode = 0x13; - signature = 0x1e 0x90 0x01; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 1; - bytedelay = 0; - pollindex = 0; - pollvalue = 0xFF; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 64; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 32; - readsize = 256; - ; - memory "flash" - size = 1024; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x02; - delay = 15; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4414 -#------------------------------------------------------------ - -part - id = "4414"; - desc = "AT90S4414"; - stk500_devcode = 0x50; - avr910_devcode = 0x28; - signature = 0x1e 0x92 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2313 -#------------------------------------------------------------ - -part - id = "2313"; - desc = "AT90S2313"; - stk500_devcode = 0x40; - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x i i x", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2333 -#------------------------------------------------------------ - -part - id = "2333"; -##### WARNING: No XML file for device 'AT90S2333'! ##### - desc = "AT90S2333"; - stk500_devcode = 0x42; - avr910_devcode = 0x34; - signature = 0x1e 0x91 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s2343 (also AT90s2323 and ATtiny22) -#------------------------------------------------------------ - -part - id = "2343"; - desc = "AT90S2343"; - stk500_devcode = 0x43; - avr910_devcode = 0x4c; - signature = 0x1e 0x91 0x03; - chip_erase_delay = 18000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 0; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 128; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s4433 -#------------------------------------------------------------ - -part - id = "4433"; - desc = "AT90S4433"; - stk500_devcode = 0x51; - avr910_devcode = 0x30; - signature = 0x1e 0x92 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4434 -#------------------------------------------------------------ - -part - id = "4434"; -##### WARNING: No XML file for device 'AT90S4434'! ##### - desc = "AT90S4434"; - stk500_devcode = 0x52; - avr910_devcode = 0x6c; - signature = 0x1e 0x92 0x02; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s8515 -#------------------------------------------------------------ - -part - id = "8515"; - desc = "AT90S8515"; - stk500_devcode = 0x60; - avr910_devcode = 0x38; - signature = 0x1e 0x93 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s8535 -#------------------------------------------------------------ - -part - id = "8535"; - desc = "AT90S8535"; - stk500_devcode = 0x61; - avr910_devcode = 0x68; - signature = 0x1e 0x93 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x x o"; - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o x x x x x x"; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# ATmega103 -#------------------------------------------------------------ - -part - id = "m103"; - desc = "ATmega103"; - stk500_devcode = 0xB1; - avr910_devcode = 0x41; - signature = 0x1e 0x97 0x01; - chip_erase_delay = 112000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x8E, 0x9E, 0x2E, 0x3E, 0xAE, 0xBE, - 0x4E, 0x5E, 0xCE, 0xDE, 0x6E, 0x7E, 0xEE, 0xDE, - 0x66, 0x76, 0xE6, 0xF6, 0x6A, 0x7A, 0xEA, 0x7A, - 0x7F, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 10; - - memory "eeprom" - size = 4096; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 22000; - max_write_delay = 56000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 70; - blocksize = 256; - readsize = 256; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o x o 1 o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 i 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega64 -#------------------------------------------------------------ - -part - id = "m64"; - desc = "ATmega64"; - has_jtag = yes; - stk500_devcode = 0xA0; - avr910_devcode = 0x45; - signature = 0x1e 0x96 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - allowfullpagebitstream = yes; - - ocdrev = 2; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega128 -#------------------------------------------------------------ - -part - id = "m128"; - desc = "ATmega128"; - has_jtag = yes; - stk500_devcode = 0xB2; - avr910_devcode = 0x43; - signature = 0x1e 0x97 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - rampz = 0x3b; - allowfullpagebitstream = yes; - - ocdrev = 1; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN128 -#------------------------------------------------------------ - -part - id = "c128"; - desc = "AT90CAN128"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x97 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN64 -#------------------------------------------------------------ - -part - id = "c64"; - desc = "AT90CAN64"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x96 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN32 -#------------------------------------------------------------ - -part - id = "c32"; - desc = "AT90CAN32"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x95 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 256; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega16 -#------------------------------------------------------------ - -part - id = "m16"; - desc = "ATmega16"; - has_jtag = yes; - stk500_devcode = 0x82; - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x03; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 100; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - ocdrev = 2; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "calibration" - size = 4; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega164P -#------------------------------------------------------------ - -# close to ATmega16 - -part parent "m16" - id = "m164p"; - desc = "ATmega164P"; - signature = 0x1e 0x94 0x0a; - - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - allowfullpagebitstream = no; - chip_erase_delay = 55000; - - ocdrev = 3; - ; - - -#------------------------------------------------------------ -# ATmega324P -#------------------------------------------------------------ - -# similar to ATmega164P - -part - id = "m324p"; - desc = "ATmega324P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x95 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 55000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega324PA -#------------------------------------------------------------ - -# similar to ATmega324P - -part parent "m324p" - id = "m324pa"; - desc = "ATmega324PA"; - signature = 0x1e 0x95 0x11; - - ocdrev = 3; - ; - - -#------------------------------------------------------------ -# ATmega644 -#------------------------------------------------------------ - -# similar to ATmega164 - -part - id = "m644"; - desc = "ATmega644"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x09; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 55000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega644P -#------------------------------------------------------------ - -# similar to ATmega164p - -part parent "m644" - id = "m644p"; - desc = "ATmega644P"; - signature = 0x1e 0x96 0x0a; - - ocdrev = 3; - ; - - - -#------------------------------------------------------------ -# ATmega1284 -#------------------------------------------------------------ - -# similar to ATmega164 - -part - id = "m1284"; - desc = "ATmega1284"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x97 0x06; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 55000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega1284P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m1284p"; - desc = "ATmega1284P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x97 0x05; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 55000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega162 -#------------------------------------------------------------ - -part - id = "m162"; - desc = "ATmega162"; - has_jtag = yes; - stk500_devcode = 0x83; - avr910_devcode = 0x63; - signature = 0x1e 0x94 0x04; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - - idr = 0x04; - spmcr = 0x57; - allowfullpagebitstream = yes; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - ocdrev = 2; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - - ; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; -; - - - -#------------------------------------------------------------ -# ATmega163 -#------------------------------------------------------------ - -part - id = "m163"; - desc = "ATmega163"; - stk500_devcode = 0x81; - avr910_devcode = 0x64; - signature = 0x1e 0x94 0x02; - chip_erase_delay = 32000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 16000; - max_write_delay = 16000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 20; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o x x o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i 1 1 i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x 1 o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x 0 x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega169 -#------------------------------------------------------------ - -part - id = "m169"; - desc = "ATmega169"; - has_jtag = yes; - stk500_devcode = 0x85; - avr910_devcode = 0x78; - signature = 0x1e 0x94 0x05; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - ocdrev = 2; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329 -#------------------------------------------------------------ - -part - id = "m329"; - desc = "ATmega329"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329P -#------------------------------------------------------------ -# Identical to ATmega329 except of the signature - -part parent "m329" - id = "m329p"; - desc = "ATmega329P"; - signature = 0x1e 0x95 0x0b; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega3290 -#------------------------------------------------------------ - -# identical to ATmega329 - -part parent "m329" - id = "m3290"; - desc = "ATmega3290"; - signature = 0x1e 0x95 0x04; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega3290P -#------------------------------------------------------------ - -# identical to ATmega3290 except of the signature - -part parent "m3290" - id = "m3290p"; - desc = "ATmega3290P"; - signature = 0x1e 0x95 0x0c; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega649 -#------------------------------------------------------------ - -part - id = "m649"; - desc = "ATmega649"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6490 -#------------------------------------------------------------ - -# identical to ATmega649 - -part parent "m649" - id = "m6490"; - desc = "ATmega6490"; - signature = 0x1e 0x96 0x04; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega32 -#------------------------------------------------------------ - -part - id = "m32"; - desc = "ATmega32"; - has_jtag = yes; - stk500_devcode = 0x91; - avr910_devcode = 0x72; - signature = 0x1e 0x95 0x02; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - ocdrev = 2; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega161 -#------------------------------------------------------------ - -part - id = "m161"; - desc = "ATmega161"; - stk500_devcode = 0x80; - avr910_devcode = 0x60; - signature = 0x1e 0x94 0x01; - chip_erase_delay = 28000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - memory "eeprom" - size = 512; - min_write_delay = 3400; - max_write_delay = 3400; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 14000; - max_write_delay = 14000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 16; - blocksize = 128; - readsize = 256; - ; - - memory "fuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x o x o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x 1 i 1 i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega8 -#------------------------------------------------------------ - -part - id = "m8"; - desc = "ATmega8"; - stk500_devcode = 0x70; - avr910_devcode = 0x76; - signature = 0x1e 0x93 0x07; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 10000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - page_size = 4; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega8515 -#------------------------------------------------------------ - -part - id = "m8515"; - desc = "ATmega8515"; - stk500_devcode = 0x63; - avr910_devcode = 0x3A; - signature = 0x1e 0x93 0x06; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega8535 -#------------------------------------------------------------ - -part - id = "m8535"; - desc = "ATmega8535"; - stk500_devcode = 0x64; - avr910_devcode = 0x69; - signature = 0x1e 0x93 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATtiny26 -#------------------------------------------------------------ - -part - id = "t26"; - desc = "ATtiny26"; - stk500_devcode = 0x21; - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x09; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 16; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x x x x i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny261 -#------------------------------------------------------------ -# Close to ATtiny26 - -part - id = "t261"; - desc = "ATtiny261"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0c; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - size = 128; - page_size = 4; - num_pages = 32; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny461 -#------------------------------------------------------------ -# Close to ATtiny261 - -part - id = "t461"; - desc = "ATtiny461"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x92 0x08; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - size = 256; - page_size = 4; - num_pages = 64; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny861 -#------------------------------------------------------------ -# Close to ATtiny461 - -part - id = "t861"; - desc = "ATtiny861"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x93 0x0d; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - size = 512; - num_pages = 128; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny28 -#------------------------------------------------------------ - -# This is an HVPP-only device. - -part - id = "t28"; - desc = "ATtiny28"; - stk500_devcode = 0x22; - avr910_devcode = 0x5c; - signature = 0x1e 0x91 0x07; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "flash" - size = 2048; - page_size = 2; - readsize = 256; - delay = 5; - ; - - memory "signature" - size = 3; - ; - - memory "lock" - size = 1; - ; - - memory "calibration" - size = 1; - ; - - memory "fuse" - size = 1; - ; -; - - - -#------------------------------------------------------------ -# ATmega48 -#------------------------------------------------------------ - -part - id = "m48"; - desc = "ATmega48"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x59; -# avr910_devcode = 0x; - signature = 0x1e 0x92 0x05; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 45000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - page_size = 4; - size = 256; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega48P -#------------------------------------------------------------ - -part parent "m48" - id = "m48p"; - desc = "ATmega48P"; - signature = 0x1e 0x92 0x0a; - - ocdrev = 1; - ; - -#------------------------------------------------------------ -# ATmega48PB -#------------------------------------------------------------ - -part parent "m48" - id = "m48pb"; - desc = "ATmega48PB"; - signature = 0x1e 0x92 0x10; - - ocdrev = 1; - ; - -#------------------------------------------------------------ -# ATmega88 -#------------------------------------------------------------ - -part - id = "m88"; - desc = "ATmega88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x0a; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega88P -#------------------------------------------------------------ - -part parent "m88" - id = "m88p"; - desc = "ATmega88P"; - signature = 0x1e 0x93 0x0f; - - ocdrev = 1; - ; - -#------------------------------------------------------------ -# ATmega88PB -#------------------------------------------------------------ - -part parent "m88" - id = "m88pb"; - desc = "ATmega88PB"; - signature = 0x1e 0x93 0x16; - - ocdrev = 1; - ; - -#------------------------------------------------------------ -# ATmega168 -#------------------------------------------------------------ - -part - id = "m168"; - desc = "ATmega168"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x94 0x06; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATmega168P -#------------------------------------------------------------ - -part parent "m168" - id = "m168p"; - desc = "ATmega168P"; - signature = 0x1e 0x94 0x0b; - - ocdrev = 1; -; - -#------------------------------------------------------------ -# ATmega168PB -#------------------------------------------------------------ - -part parent "m168" - id = "m168pb"; - desc = "ATmega168PB"; - signature = 0x1e 0x94 0x15; - - ocdrev = 1; -; - -#------------------------------------------------------------ -# ATtiny88 -#------------------------------------------------------------ - -part - id = "t88"; - desc = "ATtiny88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x11; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - page_size = 4; - size = 64; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 64; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega328 -#------------------------------------------------------------ - -part - id = "m328"; - desc = "ATmega328"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x95 0x14; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; - page_size = 4; - size = 1024; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -part parent "m328" - id = "m328p"; - desc = "ATmega328P"; - signature = 0x1e 0x95 0x0F; - - ocdrev = 1; -; - -#------------------------------------------------------------ -# ATmega32m1 -#------------------------------------------------------------ - -part parent "m328" - id = "m32m1"; - desc = "ATmega32M1"; - # stk500_devcode = 0x; - # avr910_devcode = 0x; - signature = 0x1e 0x95 0x84; - bs2 = 0xe2; - - memory "efuse" - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x i i i i i i"; - ; -; - -#------------------------------------------------------------ -# ATtiny2313 -#------------------------------------------------------------ - -part - id = "t2313"; - desc = "ATtiny2313"; - has_debugwire = yes; - flash_instr = 0xB2, 0x0F, 0x1F; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x23; -## Use the ATtiny26 devcode: - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0a; - pagel = 0xD4; - bs2 = 0xD6; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, - 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, - 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, - 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 0; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -# The Tiny2313 has calibration data for both 4 MHz and 8 MHz. -# The information in the data sheet of April/2004 is wrong, this works: - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny4313 -#------------------------------------------------------------ - -part - id = "t4313"; - desc = "ATtiny4313"; - has_debugwire = yes; - flash_instr = 0xB2, 0x0F, 0x1F; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x23; -## Use the ATtiny26 devcode: - avr910_devcode = 0x5e; - signature = 0x1e 0x92 0x0d; - pagel = 0xD4; - bs2 = 0xD6; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, - 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, - 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, - 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 0; - - memory "eeprom" - size = 256; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny4313 has Signature Bytes: 0x1E 0x92 0x0D. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2 -#------------------------------------------------------------ - -part - id = "pwm2"; - desc = "AT90PWM2"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3 -#------------------------------------------------------------ - -# Completely identical to AT90PWM2 (including the signature!) - -part parent "pwm2" - id = "pwm3"; - desc = "AT90PWM3"; - ; - -#------------------------------------------------------------ -# AT90PWM2B -#------------------------------------------------------------ -# Same as AT90PWM2 but different signature. - -part parent "pwm2" - id = "pwm2b"; - desc = "AT90PWM2B"; - signature = 0x1e 0x93 0x83; - - ocdrev = 1; - ; - -#------------------------------------------------------------ -# AT90PWM3B -#------------------------------------------------------------ - -# Completely identical to AT90PWM2B (including the signature!) - -part parent "pwm2b" - id = "pwm3b"; - desc = "AT90PWM3B"; - - ocdrev = 1; - ; - -#------------------------------------------------------------ -# AT90PWM316 -#------------------------------------------------------------ - -# Similar to AT90PWM3B, but with 16 kiB flash, 512 B EEPROM, and 1024 B SRAM. - -part parent "pwm3b" - id = "pwm316"; - desc = "AT90PWM316"; - signature = 0x1e 0x94 0x83; - - ocdrev = 1; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - ; - -#------------------------------------------------------------ -# AT90PWM216 -#------------------------------------------------------------ -# Completely identical to AT90PWM316 (including the signature!) - -part parent "pwm316" - id = "pwm216"; - desc = "AT90PWM216"; - ; - -#------------------------------------------------------------ -# ATtiny25 -#------------------------------------------------------------ - -part - id = "t25"; - desc = "ATtiny25"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x08; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 1; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny25 has Signature Bytes: 0x1E 0x91 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny45 -#------------------------------------------------------------ - -part - id = "t45"; - desc = "ATtiny45"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x06; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 1; - - memory "eeprom" - size = 256; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny45 has Signature Bytes: 0x1E 0x92 0x08. (Data sheet 2586C-AVR-06/05 (doc2586.pdf) indicates otherwise!) - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny85 -#------------------------------------------------------------ - -part - id = "t85"; - desc = "ATtiny85"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 1; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny85 has Signature Bytes: 0x1E 0x93 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega640 -#------------------------------------------------------------ -# Almost same as ATmega1280, except for different memory sizes - -part - id = "m640"; - desc = "ATmega640"; - signature = 0x1e 0x96 0x08; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1280 -#------------------------------------------------------------ - -part - id = "m1280"; - desc = "ATmega1280"; - signature = 0x1e 0x97 0x03; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1281 -#------------------------------------------------------------ -# Identical to ATmega1280 - -part parent "m1280" - id = "m1281"; - desc = "ATmega1281"; - signature = 0x1e 0x97 0x04; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega2560 -#------------------------------------------------------------ - -part - id = "m2560"; - desc = "ATmega2560"; - signature = 0x1e 0x98 0x01; - has_jtag = yes; - stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - ocdrev = 4; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2561 -#------------------------------------------------------------ - -part parent "m2560" - id = "m2561"; - desc = "ATmega2561"; - signature = 0x1e 0x98 0x02; - - ocdrev = 4; - ; - -#------------------------------------------------------------ -# ATmega128RFA1 -#------------------------------------------------------------ -# Identical to ATmega2561 but half the ROM - -part parent "m2561" - id = "m128rfa1"; - desc = "ATmega128RFA1"; - signature = 0x1e 0xa7 0x01; - chip_erase_delay = 55000; - bs2 = 0xE2; - - ocdrev = 3; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 50000; - max_write_delay = 50000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 256; - readsize = 256; - ; - ; - -#------------------------------------------------------------ -# ATmega256RFR2 -#------------------------------------------------------------ - -part parent "m2561" - id = "m256rfr2"; - desc = "ATmega256RFR2"; - signature = 0x1e 0xa8 0x02; - chip_erase_delay = 18500; - bs2 = 0xE2; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 8192; - min_write_delay = 13000; - max_write_delay = 13000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - - ocdrev = 4; - ; - -#------------------------------------------------------------ -# ATmega128RFR2 -#------------------------------------------------------------ - -part parent "m128rfa1" - id = "m128rfr2"; - desc = "ATmega128RFR2"; - signature = 0x1e 0xa7 0x02; - - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega64RFR2 -#------------------------------------------------------------ - -part parent "m128rfa1" - id = "m64rfr2"; - desc = "ATmega64RFR2"; - signature = 0x1e 0xa6 0x02; - - - ocdrev = 3; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 50000; - max_write_delay = 50000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 256; - readsize = 256; - ; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 13000; - max_write_delay = 13000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - - ; - -#------------------------------------------------------------ -# ATmega2564RFR2 -#------------------------------------------------------------ - -part parent "m256rfr2" - id = "m2564rfr2"; - desc = "ATmega2564RFR2"; - signature = 0x1e 0xa8 0x03; - ; - -#------------------------------------------------------------ -# ATmega1284RFR2 -#------------------------------------------------------------ - -part parent "m128rfr2" - id = "m1284rfr2"; - desc = "ATmega1284RFR2"; - signature = 0x1e 0xa7 0x03; - ; - -#------------------------------------------------------------ -# ATmega644RFR2 -#------------------------------------------------------------ - -part parent "m64rfr2" - id = "m644rfr2"; - desc = "ATmega644RFR2"; - signature = 0x1e 0xa6 0x03; - ; - -#------------------------------------------------------------ -# ATtiny24 -#------------------------------------------------------------ - -part - id = "t24"; - desc = "ATtiny24"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 1; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny24 has Signature Bytes: 0x1E 0x91 0x0B. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny44 -#------------------------------------------------------------ - -part - id = "t44"; - desc = "ATtiny44"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x07; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 1; - - memory "eeprom" - size = 256; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny44 has Signature Bytes: 0x1E 0x92 0x07. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny84 -#------------------------------------------------------------ - -part - id = "t84"; - desc = "ATtiny84"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0c; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - ocdrev = 1; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny84 has Signature Bytes: 0x1E 0x93 0x0C. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny43U -#------------------------------------------------------------ - -part - id = "t43u"; - desc = "ATtiny43u"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x0C; - reset = io; - chip_erase_delay = 1000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, 0x4E, 0x5E, - 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, 0x06, 0x16, 0x46, 0x56, - 0x0A, 0x1A, 0x4A, 0x5A, 0x1E, 0x7C, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 20; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - memory "eeprom" - size = 64; - paged = yes; - page_size = 4; - num_pages = 16; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "0 0 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "0 0 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " 0 0 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATmega32u4 -#------------------------------------------------------------ - -part - id = "m32u4"; - desc = "ATmega32U4"; - signature = 0x1e 0x95 0x87; - usbpid = 0x2ff4; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB646 -#------------------------------------------------------------ - -part - id = "usb646"; - desc = "AT90USB646"; - signature = 0x1e 0x96 0x82; - usbpid = 0x2ff9; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB647 -#------------------------------------------------------------ -# identical to AT90USB646 - -part parent "usb646" - id = "usb647"; - desc = "AT90USB647"; - signature = 0x1e 0x96 0x82; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# AT90USB1286 -#------------------------------------------------------------ - -part - id = "usb1286"; - desc = "AT90USB1286"; - signature = 0x1e 0x97 0x82; - usbpid = 0x2ffb; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1287 -#------------------------------------------------------------ -# identical to AT90USB1286 - -part parent "usb1286" - id = "usb1287"; - desc = "AT90USB1287"; - signature = 0x1e 0x97 0x82; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# AT90USB162 -#------------------------------------------------------------ - -part - id = "usb162"; - desc = "AT90USB162"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x94 0x82; - usbpid = 0x2ffa; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB82 -#------------------------------------------------------------ -# Changes against AT90USB162 (beside IDs) -# memory "flash" -# size = 8192; -# num_pages = 64; - -part - id = "usb82"; - desc = "AT90USB82"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x93 0x82; - usbpid = 0x2ff7; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 128; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32U2 -#------------------------------------------------------------ -# Changes against AT90USB162 (beside IDs) -# memory "flash" -# size = 32768; -# num_pages = 256; -# memory "eeprom" -# size = 1024; -# num_pages = 256; -part - id = "m32u2"; - desc = "ATmega32U2"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x95 0x8a; - usbpid = 0x2ff0; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - num_pages = 256; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; -#------------------------------------------------------------ -# ATmega16U2 -#------------------------------------------------------------ -# Changes against ATmega32U2 (beside IDs) -# memory "flash" -# size = 16384; -# num_pages = 128; -# memory "eeprom" -# size = 512; -# num_pages = 128; -part - id = "m16u2"; - desc = "ATmega16U2"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x94 0x89; - usbpid = 0x2fef; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega8U2 -#------------------------------------------------------------ -# Changes against ATmega16U2 (beside IDs) -# memory "flash" -# size = 8192; -# page_size = 64; -# blocksize = 64; - -part - id = "m8u2"; - desc = "ATmega8U2"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x93 0x89; - usbpid = 0x2fee; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - ocdrev = 1; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 128; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; -#------------------------------------------------------------ -# ATmega325 -#------------------------------------------------------------ - -part - id = "m325"; - desc = "ATmega325"; - signature = 0x1e 0x95 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega645 -#------------------------------------------------------------ - -part - id = "m645"; - desc = "ATmega645"; - signature = 0x1E 0x96 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - ocdrev = 3; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3250 -#------------------------------------------------------------ - -part parent "m325" - id = "m3250"; - desc = "ATmega3250"; - signature = 0x1E 0x95 0x06; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# ATmega6450 -#------------------------------------------------------------ - -part parent "m645" - id = "m6450"; - desc = "ATmega6450"; - signature = 0x1E 0x96 0x06; - - ocdrev = 3; - ; - -#------------------------------------------------------------ -# AVR XMEGA family common values -#------------------------------------------------------------ - -part - id = ".xmega"; - desc = "AVR XMEGA family common values"; - has_pdi = yes; - nvm_base = 0x01c0; - mcu_base = 0x0090; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "prodsig" - size = 0x32; - offset = 0x8e0200; - page_size = 0x32; - readsize = 0x32; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; - - memory "data" - # SRAM, only used to supply the offset - offset = 0x1000000; - ; -; - -#------------------------------------------------------------ -# ATxmega16A4U -#------------------------------------------------------------ - -part parent ".xmega" - id = "x16a4u"; - desc = "ATxmega16A4U"; - signature = 0x1e 0x94 0x41; - usbpid = 0x2fe3; - - memory "eeprom" - size = 0x400; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x4000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x803000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x1000; - offset = 0x804000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x5000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x100; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega16C4 -#------------------------------------------------------------ - -part parent "x16a4u" - id = "x16c4"; - desc = "ATxmega16C4"; - signature = 0x1e 0x95 0x44; -; - -#------------------------------------------------------------ -# ATxmega16D4 -#------------------------------------------------------------ - -part parent "x16a4u" - id = "x16d4"; - desc = "ATxmega16D4"; - signature = 0x1e 0x94 0x42; -; - -#------------------------------------------------------------ -# ATxmega16A4 -#------------------------------------------------------------ - -part parent "x16a4u" - id = "x16a4"; - desc = "ATxmega16A4"; - signature = 0x1e 0x94 0x41; - has_jtag = yes; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega32A4U -#------------------------------------------------------------ - -part parent ".xmega" - id = "x32a4u"; - desc = "ATxmega32A4U"; - signature = 0x1e 0x95 0x41; - usbpid = 0x2fe4; - - memory "eeprom" - size = 0x400; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x8000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x807000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x1000; - offset = 0x808000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x9000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x100; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega32C4 -#------------------------------------------------------------ - -part parent "x32a4u" - id = "x32c4"; - desc = "ATxmega32C4"; - signature = 0x1e 0x94 0x43; -; - -#------------------------------------------------------------ -# ATxmega32D4 -#------------------------------------------------------------ - -part parent "x32a4u" - id = "x32d4"; - desc = "ATxmega32D4"; - signature = 0x1e 0x95 0x42; -; - -#------------------------------------------------------------ -# ATxmega32A4 -#------------------------------------------------------------ - -part parent "x32a4u" - id = "x32a4"; - desc = "ATxmega32A4"; - signature = 0x1e 0x95 0x41; - has_jtag = yes; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega64A4U -#------------------------------------------------------------ - -part parent ".xmega" - id = "x64a4u"; - desc = "ATxmega64A4U"; - signature = 0x1e 0x96 0x46; - usbpid = 0x2fe5; - - memory "eeprom" - size = 0x800; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x10000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x80f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x1000; - offset = 0x810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x11000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x100; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega64C3 -#------------------------------------------------------------ - -part parent "x64a4u" - id = "x64c3"; - desc = "ATxmega64C3"; - signature = 0x1e 0x96 0x49; - usbpid = 0x2fd6; -; - -#------------------------------------------------------------ -# ATxmega64D3 -#------------------------------------------------------------ - -part parent "x64a4u" - id = "x64d3"; - desc = "ATxmega64D3"; - signature = 0x1e 0x96 0x4a; -; - -#------------------------------------------------------------ -# ATxmega64D4 -#------------------------------------------------------------ - -part parent "x64a4u" - id = "x64d4"; - desc = "ATxmega64D4"; - signature = 0x1e 0x96 0x47; -; - -#------------------------------------------------------------ -# ATxmega64A1 -#------------------------------------------------------------ - -part parent "x64a4u" - id = "x64a1"; - desc = "ATxmega64A1"; - signature = 0x1e 0x96 0x4e; - has_jtag = yes; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega64A1U -#------------------------------------------------------------ - -part parent "x64a1" - id = "x64a1u"; - desc = "ATxmega64A1U"; - signature = 0x1e 0x96 0x4e; - usbpid = 0x2fe8; -; - -#------------------------------------------------------------ -# ATxmega64A3 -#------------------------------------------------------------ - -part parent "x64a1" - id = "x64a3"; - desc = "ATxmega64A3"; - signature = 0x1e 0x96 0x42; -; - -#------------------------------------------------------------ -# ATxmega64A3U -#------------------------------------------------------------ - -part parent "x64a1" - id = "x64a3u"; - desc = "ATxmega64A3U"; - signature = 0x1e 0x96 0x42; - usbpid = 0x2fe5; -; - -#------------------------------------------------------------ -# ATxmega64A4 -#------------------------------------------------------------ - -part parent "x64a1" - id = "x64a4"; - desc = "ATxmega64A4"; - signature = 0x1e 0x96 0x46; -; - -#------------------------------------------------------------ -# ATxmega64B1 -#------------------------------------------------------------ - -part parent "x64a1" - id = "x64b1"; - desc = "ATxmega64B1"; - signature = 0x1e 0x96 0x52; - usbpid = 0x2fe1; -; - -#------------------------------------------------------------ -# ATxmega64B3 -#------------------------------------------------------------ - -part parent "x64a1" - id = "x64b3"; - desc = "ATxmega64B3"; - signature = 0x1e 0x96 0x51; - usbpid = 0x2fdf; -; - -#------------------------------------------------------------ -# ATxmega128C3 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x128c3"; - desc = "ATxmega128C3"; - signature = 0x1e 0x97 0x52; - usbpid = 0x2fd7; - - memory "eeprom" - size = 0x800; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x20000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "apptable" - size = 0x2000; - offset = 0x81e000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x820000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "flash" - size = 0x22000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x200; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega128D3 -#------------------------------------------------------------ - -part parent "x128c3" - id = "x128d3"; - desc = "ATxmega128D3"; - signature = 0x1e 0x97 0x48; -; - -#------------------------------------------------------------ -# ATxmega128D4 -#------------------------------------------------------------ - -part parent "x128c3" - id = "x128d4"; - desc = "ATxmega128D4"; - signature = 0x1e 0x97 0x47; -; - -#------------------------------------------------------------ -# ATxmega128A1 -#------------------------------------------------------------ - -part parent "x128c3" - id = "x128a1"; - desc = "ATxmega128A1"; - signature = 0x1e 0x97 0x4c; - has_jtag = yes; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega128A1 revision D -#------------------------------------------------------------ - -part parent "x128a1" - id = "x128a1d"; - desc = "ATxmega128A1revD"; - signature = 0x1e 0x97 0x41; -; - -#------------------------------------------------------------ -# ATxmega128A1U -#------------------------------------------------------------ - -part parent "x128a1" - id = "x128a1u"; - desc = "ATxmega128A1U"; - signature = 0x1e 0x97 0x4c; - usbpid = 0x2fed; -; - -#------------------------------------------------------------ -# ATxmega128A3 -#------------------------------------------------------------ - -part parent "x128a1" - id = "x128a3"; - desc = "ATxmega128A3"; - signature = 0x1e 0x97 0x42; -; - -#------------------------------------------------------------ -# ATxmega128A3U -#------------------------------------------------------------ - -part parent "x128a1" - id = "x128a3u"; - desc = "ATxmega128A3U"; - signature = 0x1e 0x97 0x42; - usbpid = 0x2fe6; -; - -#------------------------------------------------------------ -# ATxmega128A4 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x128a4"; - desc = "ATxmega128A4"; - signature = 0x1e 0x97 0x46; - has_jtag = yes; - - memory "eeprom" - size = 0x800; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x20000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x81f000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x820000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "flash" - size = 0x22000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x200; - readsize = 0x100; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega128A4U -#------------------------------------------------------------ - -part parent ".xmega" - id = "x128a4u"; - desc = "ATxmega128A4U"; - signature = 0x1e 0x97 0x46; - usbpid = 0x2fde; - - memory "eeprom" - size = 0x800; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x20000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x81f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x22000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x100; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega128B1 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x128b1"; - desc = "ATxmega128B1"; - signature = 0x1e 0x97 0x4d; - usbpid = 0x2fea; - has_jtag = yes; - - memory "eeprom" - size = 0x800; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x20000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x2000; - offset = 0x81e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x22000; - offset = 0x800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x100; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega128B3 -#------------------------------------------------------------ - -part parent "x128b1" - id = "x128b3"; - desc = "ATxmega128B3"; - signature = 0x1e 0x97 0x4b; - usbpid = 0x2fe0; -; - -#------------------------------------------------------------ -# ATxmega192C3 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x192c3"; - desc = "ATxmega192C3"; - signature = 0x1e 0x97 0x51; - # usbpid = 0x2f??; - - memory "eeprom" - size = 0x800; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x30000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "apptable" - size = 0x2000; - offset = 0x82e000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x830000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "flash" - size = 0x32000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x200; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega192D3 -#------------------------------------------------------------ - -part parent "x192c3" - id = "x192d3"; - desc = "ATxmega192D3"; - signature = 0x1e 0x97 0x49; -; - -#------------------------------------------------------------ -# ATxmega192A1 -#------------------------------------------------------------ - -part parent "x192c3" - id = "x192a1"; - desc = "ATxmega192A1"; - signature = 0x1e 0x97 0x4e; - has_jtag = yes; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega192A3 -#------------------------------------------------------------ - -part parent "x192a1" - id = "x192a3"; - desc = "ATxmega192A3"; - signature = 0x1e 0x97 0x44; -; - -#------------------------------------------------------------ -# ATxmega192A3U -#------------------------------------------------------------ - -part parent "x192a1" - id = "x192a3u"; - desc = "ATxmega192A3U"; - signature = 0x1e 0x97 0x44; - usbpid = 0x2fe7; -; - -#------------------------------------------------------------ -# ATxmega256C3 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x256c3"; - desc = "ATxmega256C3"; - signature = 0x1e 0x98 0x46; - usbpid = 0x2fda; - - memory "eeprom" - size = 0x1000; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x40000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "apptable" - size = 0x2000; - offset = 0x83e000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x840000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "flash" - size = 0x42000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x200; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega256D3 -#------------------------------------------------------------ - -part parent "x256c3" - id = "x256d3"; - desc = "ATxmega256D3"; - signature = 0x1e 0x98 0x44; -; - -#------------------------------------------------------------ -# ATxmega256A1 -#------------------------------------------------------------ - -part parent "x256c3" - id = "x256a1"; - desc = "ATxmega256A1"; - signature = 0x1e 0x98 0x46; - has_jtag = yes; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; -; - -#------------------------------------------------------------ -# ATxmega256A3 -#------------------------------------------------------------ - -part parent "x256a1" - id = "x256a3"; - desc = "ATxmega256A3"; - signature = 0x1e 0x98 0x42; -; - -#------------------------------------------------------------ -# ATxmega256A3U -#------------------------------------------------------------ - -part parent "x256a1" - id = "x256a3u"; - desc = "ATxmega256A3U"; - signature = 0x1e 0x98 0x42; - usbpid = 0x2fec; -; - -#------------------------------------------------------------ -# ATxmega256A3B -#------------------------------------------------------------ - -part parent "x256a1" - id = "x256a3b"; - desc = "ATxmega256A3B"; - signature = 0x1e 0x98 0x43; -; - -#------------------------------------------------------------ -# ATxmega256A3BU -#------------------------------------------------------------ - -part parent "x256a1" - id = "x256a3bu"; - desc = "ATxmega256A3BU"; - signature = 0x1e 0x98 0x43; - usbpid = 0x2fe2; -; - -#------------------------------------------------------------ -# ATxmega384C3 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x384c3"; - desc = "ATxmega384C3"; - signature = 0x1e 0x98 0x45; - usbpid = 0x2fdb; - - memory "eeprom" - size = 0x1000; - offset = 0x8c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x60000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "apptable" - size = 0x2000; - offset = 0x85e000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "boot" - size = 0x2000; - offset = 0x860000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "flash" - size = 0x62000; - offset = 0x800000; - page_size = 0x200; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x200; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega384D3 -#------------------------------------------------------------ - -part parent "x384c3" - id = "x384d3"; - desc = "ATxmega384D3"; - signature = 0x1e 0x98 0x47; -; - -#------------------------------------------------------------ -# ATxmega8E5 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x8e5"; - desc = "ATxmega8E5"; - signature = 0x1e 0x93 0x41; - - memory "eeprom" - size = 0x0200; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x2000; - offset = 0x0800000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "apptable" - size = 0x800; - offset = 0x00801800; - page_size = 0x80; - readsize = 0x100; - ; - - memory "boot" - size = 0x800; - offset = 0x00802000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "flash" - size = 0x2800; - offset = 0x0800000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "usersig" - size = 0x80; - offset = 0x8e0400; - page_size = 0x80; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega16E5 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x16e5"; - desc = "ATxmega16E5"; - signature = 0x1e 0x94 0x45; - - memory "eeprom" - size = 0x0200; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x4000; - offset = 0x0800000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x00803000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "boot" - size = 0x1000; - offset = 0x00804000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "flash" - size = 0x5000; - offset = 0x0800000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "usersig" - size = 0x80; - offset = 0x8e0400; - page_size = 0x80; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# ATxmega32E5 -#------------------------------------------------------------ - -part parent ".xmega" - id = "x32e5"; - desc = "ATxmega32E5"; - signature = 0x1e 0x95 0x4c; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x8000; - offset = 0x0800000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "apptable" - size = 0x1000; - offset = 0x00807000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "boot" - size = 0x1000; - offset = 0x00808000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "flash" - size = 0x9000; - offset = 0x0800000; - page_size = 0x80; - readsize = 0x100; - ; - - memory "usersig" - size = 0x80; - offset = 0x8e0400; - page_size = 0x80; - readsize = 0x100; - ; -; - -#------------------------------------------------------------ -# AVR32UC3A0512 -#------------------------------------------------------------ - -part - id = "uc3a0512"; - desc = "AT32UC3A0512"; - signature = 0xED 0xC0 0x3F; - has_jtag = yes; - is_avr32 = yes; - - memory "flash" - paged = yes; - page_size = 512; # bytes - readsize = 512; # bytes - num_pages = 1024; # could be set dynamicly - size = 0x00080000; # could be set dynamicly - offset = 0x80000000; - ; -; - -part parent "uc3a0512" - id = "ucr2"; - desc = "deprecated, use 'uc3a0512'"; -; - -#------------------------------------------------------------ -# ATtiny1634. -#------------------------------------------------------------ - -part - id = "t1634"; - desc = "ATtiny1634"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x94 0x12; - pagel = 0xB3; - bs2 = 0xB1; - reset = io; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, - 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, - 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, - 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 256; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 32; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 1 1 1 1 i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# Common values for reduced core tinys (4/5/9/10/20/40) -#------------------------------------------------------------ - -part - id = ".reduced_core_tiny"; - desc = "Common values for reduced core tinys"; - has_tpi = yes; - - memory "signature" - size = 3; - offset = 0x3fc0; - page_size = 16; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - page_size = 16; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - page_size = 16; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - page_size = 16; - ; -; - -#------------------------------------------------------------ -# ATtiny4 -#------------------------------------------------------------ - -part parent ".reduced_core_tiny" - id = "t4"; - desc = "ATtiny4"; - signature = 0x1e 0x8f 0x0a; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; -; - -#------------------------------------------------------------ -# ATtiny5 -#------------------------------------------------------------ - -part parent "t4" - id = "t5"; - desc = "ATtiny5"; - signature = 0x1e 0x8f 0x09; -; - -#------------------------------------------------------------ -# ATtiny9 -#------------------------------------------------------------ - -part parent ".reduced_core_tiny" - id = "t9"; - desc = "ATtiny9"; - signature = 0x1e 0x90 0x08; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; -; - -#------------------------------------------------------------ -# ATtiny10 -#------------------------------------------------------------ - -part parent "t9" - id = "t10"; - desc = "ATtiny10"; - signature = 0x1e 0x90 0x03; -; - -#------------------------------------------------------------ -# ATtiny20 -#------------------------------------------------------------ - -part parent ".reduced_core_tiny" - id = "t20"; - desc = "ATtiny20"; - signature = 0x1e 0x91 0x0F; - - memory "flash" - size = 2048; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; -; - -#------------------------------------------------------------ -# ATtiny40 -#------------------------------------------------------------ - -part parent ".reduced_core_tiny" - id = "t40"; - desc = "ATtiny40"; - signature = 0x1e 0x92 0x0E; - - memory "flash" - size = 4096; - offset = 0x4000; - page_size = 64; - blocksize = 128; - ; -; - -#------------------------------------------------------------ -# ATmega406 -#------------------------------------------------------------ - -part - id = "m406"; - desc = "ATMEGA406"; - has_jtag = yes; - signature = 0x1e 0x95 0x07; - - # STK500 parameters (parallel programming IO lines) - pagel = 0xa7; - bs2 = 0xa0; - serial = no; - parallel = yes; - - # STK500v2 HV programming parameters, from XML - pp_controlstack = 0x0e, 0x1e, 0x0f, 0x1f, 0x2e, 0x3e, 0x2f, 0x3f, - 0x4e, 0x5e, 0x4f, 0x5f, 0x6e, 0x7e, 0x6f, 0x7f, - 0x66, 0x76, 0x67, 0x77, 0x6a, 0x7a, 0x6b, 0x7b, - 0xbe, 0xfd, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - - # JTAG ICE mkII parameters, also from XML files - allowfullpagebitstream = no; - enablepageprogramming = yes; - idr = 0x51; - rampz = 0x00; - spmcr = 0x57; - eecr = 0x3f; - - memory "eeprom" - paged = no; - size = 512; - page_size = 4; - blocksize = 4; - readsize = 4; - num_pages = 128; - ; - - memory "flash" - paged = yes; - size = 40960; - page_size = 128; - blocksize = 128; - readsize = 128; - num_pages = 320; - ; - - memory "hfuse" - size = 1; - ; - - memory "lfuse" - size = 1; - ; - - memory "lockbits" - size = 1; - ; - - memory "signature" - size = 3; - ; -; - - diff --git a/resources/fonts/NotoSans-hinted.zip b/resources/fonts/NotoSans-hinted.zip deleted file mode 100644 index 861c1be8c..000000000 Binary files a/resources/fonts/NotoSans-hinted.zip and /dev/null differ diff --git a/resources/icons/bed/mk2.svg b/resources/icons/bed/mk2.svg new file mode 100644 index 000000000..b8fa8d0cd --- /dev/null +++ b/resources/icons/bed/mk2.svg @@ -0,0 +1 @@ +MK2_bottom \ No newline at end of file diff --git a/resources/icons/bed/mk3.svg b/resources/icons/bed/mk3.svg new file mode 100644 index 000000000..c8f53373b --- /dev/null +++ b/resources/icons/bed/mk3.svg @@ -0,0 +1 @@ +MK3_bottom \ No newline at end of file diff --git a/resources/icons/bed/sl1.svg b/resources/icons/bed/sl1.svg new file mode 100644 index 000000000..c1098b9df --- /dev/null +++ b/resources/icons/bed/sl1.svg @@ -0,0 +1 @@ +SL1_Bottom \ No newline at end of file diff --git a/resources/icons/printers/PrusaResearch_MK2.5.png b/resources/icons/printers/PrusaResearch_MK2.5.png index efbbc598d..d9bf3260d 100644 Binary files a/resources/icons/printers/PrusaResearch_MK2.5.png and b/resources/icons/printers/PrusaResearch_MK2.5.png differ diff --git a/resources/icons/printers/PrusaResearch_MK2.5MMU2.png b/resources/icons/printers/PrusaResearch_MK2.5MMU2.png index eb5dccf08..7d6e9fede 100644 Binary files a/resources/icons/printers/PrusaResearch_MK2.5MMU2.png and b/resources/icons/printers/PrusaResearch_MK2.5MMU2.png differ diff --git a/resources/icons/printers/PrusaResearch_MK2.5S.png b/resources/icons/printers/PrusaResearch_MK2.5S.png new file mode 100644 index 000000000..d9bf3260d Binary files /dev/null and b/resources/icons/printers/PrusaResearch_MK2.5S.png differ diff --git a/resources/icons/printers/PrusaResearch_MK2.5SMMU2S.png b/resources/icons/printers/PrusaResearch_MK2.5SMMU2S.png new file mode 100644 index 000000000..7d6e9fede Binary files /dev/null and b/resources/icons/printers/PrusaResearch_MK2.5SMMU2S.png differ diff --git a/resources/icons/printers/PrusaResearch_MK3.png b/resources/icons/printers/PrusaResearch_MK3.png index 5279ba01e..5fa1a665b 100644 Binary files a/resources/icons/printers/PrusaResearch_MK3.png and b/resources/icons/printers/PrusaResearch_MK3.png differ diff --git a/resources/icons/printers/PrusaResearch_MK3S.png b/resources/icons/printers/PrusaResearch_MK3S.png new file mode 100644 index 000000000..5fa1a665b Binary files /dev/null and b/resources/icons/printers/PrusaResearch_MK3S.png differ diff --git a/resources/icons/printers/PrusaResearch_MK3SMMU2S.png b/resources/icons/printers/PrusaResearch_MK3SMMU2S.png new file mode 100644 index 000000000..eb5dccf08 Binary files /dev/null and b/resources/icons/printers/PrusaResearch_MK3SMMU2S.png differ diff --git a/resources/icons/printers/PrusaResearch_SL1.png b/resources/icons/printers/PrusaResearch_SL1.png index 281d7a620..3c15f95ea 100644 Binary files a/resources/icons/printers/PrusaResearch_SL1.png and b/resources/icons/printers/PrusaResearch_SL1.png differ diff --git a/resources/localization/uk/Slic3rPE.mo b/resources/localization/uk/Slic3rPE.mo index 56af728d6..8c5c5437b 100644 Binary files a/resources/localization/uk/Slic3rPE.mo and b/resources/localization/uk/Slic3rPE.mo differ diff --git a/resources/localization/uk/Slic3rPE_uk.po b/resources/localization/uk/Slic3rPE_uk.po index 9db2b919a..3845994bf 100644 --- a/resources/localization/uk/Slic3rPE_uk.po +++ b/resources/localization/uk/Slic3rPE_uk.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-01-17 13:39+0100\n" -"PO-Revision-Date: 2019-01-21 11:25+0100\n" +"PO-Revision-Date: 2019-02-26 10:38+0100\n" "Last-Translator: Oleksandra Iushchenko \n" "Language-Team: \n" "Language: uk\n" @@ -51,6 +51,12 @@ msgstr "Відстань координат 0,0 G-коду від нижньог msgid "Circular" msgstr "Круговий" +msgid "Switch to %s mode" +msgstr "Перейти до режиму %s" + +msgid "Current mode is %s" +msgstr "Поточний режим - %s" + #: src/slic3r/GUI/BedShapeDialog.cpp:69 src/slic3r/GUI/ConfigWizard.cpp:92 #: src/slic3r/GUI/ConfigWizard.cpp:456 src/slic3r/GUI/ConfigWizard.cpp:470 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:204 @@ -624,48 +630,48 @@ msgstr "" #: src/slic3r/GUI/GLGizmo.cpp:2207 msgid "Left mouse click - add point" -msgstr "" +msgstr "Ліва кнопка миші - додати точку" #: src/slic3r/GUI/GLGizmo.cpp:2208 msgid "Right mouse click - remove point" -msgstr "" +msgstr "Права кнопка миші - видалити точку" #: src/slic3r/GUI/GLGizmo.cpp:2211 msgid "Generate points automatically" -msgstr "" +msgstr "Генерувати точки автоматично" #: src/slic3r/GUI/GLGizmo.cpp:2212 msgid "Remove all points" -msgstr "" +msgstr "Видалити всі точки" #: src/slic3r/GUI/GLGizmo.cpp:2245 msgid "SLA Support Points" -msgstr "" +msgstr "Точки SLA підтримки" #: src/slic3r/GUI/GLGizmo.cpp:2268 src/slic3r/GUI/GLGizmo.cpp:2468 msgid "Rotate lower part upwards" -msgstr "" +msgstr "Повернути нижню частину вгору" #: src/slic3r/GUI/GLGizmo.cpp:2269 src/slic3r/GUI/GLGizmo.cpp:2470 msgid "Perform cut" -msgstr "" +msgstr "Виконати розріз" #: src/slic3r/GUI/GLGizmo.cpp:2276 msgid "Cut object:" -msgstr "" +msgstr "Розрізати об'єкт:" #: src/slic3r/GUI/GLGizmo.cpp:2356 src/slic3r/GUI/GLGizmo.cpp:2461 #: src/libslic3r/PrintConfig.cpp:3016 msgid "Cut" -msgstr "" +msgstr "Розрізати" #: src/slic3r/GUI/GLGizmo.cpp:2466 msgid "Keep upper part" -msgstr "" +msgstr "Залишити верхню частину" #: src/slic3r/GUI/GLGizmo.cpp:2467 msgid "Keep lower part" -msgstr "" +msgstr "Залишити нижню частину" #: src/slic3r/GUI/GUI.cpp:242 msgid "Notice" @@ -730,11 +736,11 @@ msgstr "Преференції застосування" #: src/slic3r/GUI/GUI_App.cpp:616 msgid "Simple" -msgstr "" +msgstr "Простий" #: src/slic3r/GUI/GUI_App.cpp:616 msgid "Simple View Mode" -msgstr "" +msgstr "Простий режим перегляду" #: src/slic3r/GUI/GUI_App.cpp:617 src/slic3r/GUI/GUI_ObjectList.cpp:39 #: src/slic3r/GUI/Tab.cpp:948 src/slic3r/GUI/Tab.cpp:962 @@ -747,23 +753,23 @@ msgstr "Розширений" #: src/slic3r/GUI/GUI_App.cpp:617 msgid "Advanced View Mode" -msgstr "" +msgstr "Розширений режим перегляду" #: src/slic3r/GUI/GUI_App.cpp:618 msgid "Expert" -msgstr "" +msgstr "Експерт" #: src/slic3r/GUI/GUI_App.cpp:618 msgid "Expert View Mode" -msgstr "" +msgstr "Режим перегляду Експерт" #: src/slic3r/GUI/GUI_App.cpp:620 msgid "Mode" -msgstr "" +msgstr "Режим" #: src/slic3r/GUI/GUI_App.cpp:620 msgid "Slic3r View Mode" -msgstr "" +msgstr "Режим перегляду Slic3r'у" #: src/slic3r/GUI/GUI_App.cpp:622 msgid "Change Application &Language" @@ -1752,7 +1758,7 @@ msgstr "Вид" #: src/slic3r/GUI/MainFrame.cpp:445 msgid "&Help" -msgstr "Доромога" +msgstr "Допомога" #: src/slic3r/GUI/MainFrame.cpp:472 msgid "Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):" @@ -5064,11 +5070,11 @@ msgstr "Вертикальна відстань між об'єктом та ін #: src/libslic3r/PrintConfig.cpp:1923 msgid "soluble" -msgstr "" +msgstr "розчинний" #: src/libslic3r/PrintConfig.cpp:1924 msgid "detachable" -msgstr "" +msgstr "відривний" #: src/libslic3r/PrintConfig.cpp:1929 msgid "Enforce support for the first" @@ -5636,7 +5642,7 @@ msgstr "" #: src/libslic3r/PrintConfig.cpp:3017 msgid "Cut model at the given Z." -msgstr "" +msgstr "Розрізати модель за заданим Z." #: src/libslic3r/PrintConfig.cpp:3022 msgid "Dont arrange" @@ -5672,7 +5678,7 @@ msgstr "" #: src/libslic3r/PrintConfig.cpp:3050 msgid "Help" -msgstr "" +msgstr "Допомога" #: src/libslic3r/PrintConfig.cpp:3051 msgid "Show this help." diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index a8d169c68..407883544 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,8 +1,15 @@ +min_slic3r_version = 1.42.0-alpha6 +0.8.0-alpha7 +0.8.0-alpha6 min_slic3r_version = 1.42.0-alpha +0.8.0-alpha 0.4.0-alpha4 Updated SLA profiles 0.4.0-alpha3 Update of SLA profiles 0.4.0-alpha2 First SLA profiles +min_slic3r_version = 1.41.3-alpha +0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt min_slic3r_version = 1.41.1 +0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.3.3 Prusament PETG released 0.3.2 New MK2.5 and MK3 FW versions 0.3.1 New MK2.5 and MK3 FW versions @@ -34,6 +41,7 @@ min_slic3r_version = 1.41.0-alpha 0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0 0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters min_slic3r_version = 1.40.0 +0.1.12 New MK2.5 and MK3 FW versions 0.1.11 fw version changed to 3.3.1 0.1.10 MK3 jerk and acceleration update 0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index b62567754..1b7603a94 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the Slic3r configuration to be downgraded. -config_version = 0.4.0-alpha4 +config_version = 0.8.0-alpha7 # Where to get the updates from? config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/ @@ -15,40 +15,71 @@ config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/ma #for example by the melt zone size, or whether the nozzle is hardened. # Printer model name will be shown by the installation wizard. +[printer_model:MK3S] +name = Original Prusa i3 MK3S +variants = 0.4; 0.25; 0.6 +technology = FFF +family = MK3 + [printer_model:MK3] name = Original Prusa i3 MK3 variants = 0.4; 0.25; 0.6 technology = FFF +family = MK3 + +[printer_model:MK3SMMU2S] +name = Original Prusa i3 MK3S MMU2S +variants = 0.4 +technology = FFF +family = MK3 + +[printer_model:MK3MMU2] +name = Original Prusa i3 MK3 MMU2 +variants = 0.4 +technology = FFF +family = MK3 + +[printer_model:MK2.5S] +name = Original Prusa i3 MK2.5S +variants = 0.4; 0.25; 0.6 +technology = FFF +family = MK2.5 [printer_model:MK2.5] name = Original Prusa i3 MK2.5 variants = 0.4; 0.25; 0.6 technology = FFF +family = MK2.5 -[printer_model:MK2S] -name = Original Prusa i3 MK2/S -variants = 0.4; 0.25; 0.6 -technology = FFF - -[printer_model:MK3MMU2] -name = Original Prusa i3 MK3 MMU 2.0 +[printer_model:MK2.5SMMU2S] +name = Original Prusa i3 MK2.5S MMU2S variants = 0.4 technology = FFF - -[printer_model:MK2SMM] -name = Original Prusa i3 MK2/S MMU 1.0 -variants = 0.4; 0.6 -technology = FFF +family = MK2.5 [printer_model:MK2.5MMU2] -name = Original Prusa i3 MK2.5 MMU 2.0 +name = Original Prusa i3 MK2.5 MMU2 variants = 0.4 technology = FFF +family = MK2.5 + +[printer_model:MK2S] +name = Original Prusa i3 MK2S +variants = 0.4; 0.25; 0.6 +technology = FFF +family = MK2 + +[printer_model:MK2SMM] +name = Original Prusa i3 MK2S MMU1 +variants = 0.4; 0.6 +technology = FFF +family = MK2 [printer_model:SL1] name = Original Prusa SL1 variants = default technology = SLA +family = SL1 # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -112,7 +143,7 @@ post_process = print_settings_id = raft_layers = 0 resolution = 0 -seam_position = nearest +seam_position = hidden single_extruder_multi_material_priming = 1 skirts = 1 skirt_distance = 2 @@ -204,6 +235,7 @@ support_material_interface_spacing = 0.1 support_material_synchronize_layers = 1 support_material_threshold = 80 support_material_with_sheath = 1 +wipe_tower_bridging = 8 # XXXXXXXXXXXXXXXXXXXX # XXX--- 0.05mm ---XXX @@ -239,11 +271,15 @@ inherits = *0.05mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1 infill_extrusion_width = 0.5 +# MK3 # [print:0.05mm ULTRADETAIL MK3] inherits = *0.05mm*; *MK3* +fill_pattern = gyroid +fill_density = 15% compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material top_infill_extrusion_width = 0.4 +# MK2 # [print:0.05mm ULTRADETAIL 0.25 nozzle] inherits = *0.05mm*; *0.25nozzle* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 @@ -255,14 +291,53 @@ small_perimeter_speed = 15 solid_infill_speed = 20 support_material_speed = 20 +# MK3 # [print:0.05mm ULTRADETAIL 0.25 nozzle MK3] inherits = *0.05mm*; *0.25nozzle*; *MK3* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 +# XXXXXXXXXXXXXXXXXXXX +# XXX--- 0.07mm ---XXX +# XXXXXXXXXXXXXXXXXXXX + +[print:*0.07mm*] +inherits = *common* +bottom_solid_layers = 8 +bridge_acceleration = 300 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +default_acceleration = 500 +external_perimeter_speed = 20 +fill_density = 15% +first_layer_acceleration = 500 +gap_fill_speed = 20 +infill_acceleration = 800 +infill_speed = 40 +max_print_speed = 80 +small_perimeter_speed = 20 +solid_infill_speed = 40 +support_material_extrusion_width = 0.3 +support_material_spacing = 1.5 +layer_height = 0.07 +perimeter_acceleration = 300 +perimeter_speed = 30 +perimeters = 3 +support_material_speed = 40 +top_solid_infill_speed = 30 +top_solid_layers = 11 + +# MK3 # +[print:0.07mm ULTRADETAIL MK3] +inherits = *0.07mm*; *MK3* +fill_pattern = gyroid +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material +top_infill_extrusion_width = 0.4 + # XXXXXXXXXXXXXXXXXXXX # XXX--- 0.10mm ---XXX # XXXXXXXXXXXXXXXXXXXX +# MK2 # [print:*0.10mm*] inherits = *common* bottom_solid_layers = 7 @@ -272,6 +347,7 @@ layer_height = 0.1 perimeter_acceleration = 800 top_solid_layers = 9 +# MK2 # [print:0.10mm DETAIL] inherits = *0.10mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1 @@ -281,19 +357,23 @@ infill_speed = 60 perimeter_speed = 50 solid_infill_speed = 50 +# MK3 # [print:0.10mm DETAIL MK3] inherits = *0.10mm*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material -external_perimeter_speed = 35 +external_perimeter_speed = 25 infill_acceleration = 1250 -infill_speed = 200 +infill_speed = 80 max_print_speed = 200 perimeter_speed = 45 -solid_infill_speed = 200 +solid_infill_speed = 80 top_infill_extrusion_width = 0.4 -top_solid_infill_speed = 50 +top_solid_infill_speed = 40 +fill_pattern = gyroid +fill_density = 15% +# MK2 # [print:0.10mm DETAIL 0.25 nozzle] inherits = *0.10mm*; *0.25nozzle* bridge_acceleration = 600 @@ -307,6 +387,7 @@ small_perimeter_speed = 15 solid_infill_speed = 40 top_solid_infill_speed = 30 +# MK3 # [print:0.10mm DETAIL 0.25 nozzle MK3] inherits = *0.10mm*; *0.25nozzle*; *MK3* bridge_speed = 30 @@ -319,6 +400,7 @@ perimeter_speed = 45 solid_infill_speed = 200 top_solid_infill_speed = 50 +# MK3 # [print:0.10mm DETAIL 0.6 nozzle MK3] inherits = *0.10mm*; *0.6nozzle*; *MK3* bridge_speed = 30 @@ -348,6 +430,7 @@ solid_infill_speed = 50 top_infill_extrusion_width = 0.4 top_solid_layers = 7 +# MK2 # [print:0.15mm 100mms Linear Advance] inherits = *0.15mm* bridge_flow_ratio = 0.95 @@ -361,11 +444,13 @@ solid_infill_speed = 100 support_material_speed = 60 top_solid_infill_speed = 70 +# MK2 # [print:0.15mm OPTIMAL] inherits = *0.15mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 top_infill_extrusion_width = 0.45 +# MK2 # [print:0.15mm OPTIMAL 0.25 nozzle] inherits = *0.15mm*; *0.25nozzle* bridge_acceleration = 600 @@ -380,11 +465,27 @@ small_perimeter_speed = 15 solid_infill_speed = 40 top_solid_infill_speed = 30 +# MK2 # [print:0.15mm OPTIMAL 0.6 nozzle] inherits = *0.15mm*; *0.6nozzle* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 -[print:0.15mm OPTIMAL MK3] +# MK3 # +[print:0.15mm QUALITY MK3] +inherits = *0.15mm*; *MK3* +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 +external_perimeter_speed = 25 +infill_acceleration = 1250 +infill_speed = 80 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 80 +top_solid_infill_speed = 40 +fill_pattern = gyroid +fill_density = 15% + +[print:0.15mm SPEED MK3] inherits = *0.15mm*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 @@ -392,14 +493,15 @@ external_perimeter_speed = 35 infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 -perimeter_speed = 45 +perimeter_speed = 60 solid_infill_speed = 200 top_solid_infill_speed = 50 -[print:0.15mm OPTIMAL MK3 SOLUBLE FULL] -inherits = 0.15mm OPTIMAL MK3; *soluble_support* +# MK3 MMU # +[print:0.15mm SOLUBLE FULL MK3] +inherits = 0.15mm SPEED MK3; *soluble_support* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 -notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder support_material_extruder = 5 support_material_interface_extruder = 5 perimeter_speed = 40 @@ -407,31 +509,35 @@ solid_infill_speed = 40 top_infill_extrusion_width = 0.45 top_solid_infill_speed = 30 -[print:0.15mm OPTIMAL MK3 SOLUBLE INTERFACE] -inherits = 0.15mm OPTIMAL MK3 SOLUBLE FULL -notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +# MK3 MMU # +[print:0.15mm SOLUBLE INTERFACE MK3] +inherits = 0.15mm SOLUBLE FULL MK3 +notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 +# MK2 MMU # [print:0.15mm OPTIMAL SOLUBLE FULL] inherits = *0.15mm*; *soluble_support* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1 external_perimeter_speed = 25 -notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder perimeter_speed = 40 solid_infill_speed = 40 top_infill_extrusion_width = 0.45 top_solid_infill_speed = 30 +# MK2 MMU # [print:0.15mm OPTIMAL SOLUBLE INTERFACE] inherits = 0.15mm OPTIMAL SOLUBLE FULL -notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 support_material_xy_spacing = 80% +# MK3 # [print:0.15mm OPTIMAL 0.25 nozzle MK3] inherits = *0.15mm*; *0.25nozzle*; *MK3* bridge_speed = 30 @@ -458,6 +564,7 @@ solid_infill_speed = 50 top_infill_extrusion_width = 0.4 top_solid_layers = 5 +# MK3 # [print:0.15mm OPTIMAL 0.6 nozzle MK3] inherits = *0.15mm*; *0.6nozzle*; *MK3* bridge_speed = 30 @@ -474,6 +581,7 @@ top_solid_infill_speed = 50 # XXX--- 0.20mm ---XXX # XXXXXXXXXXXXXXXXXXXX +# MK2 # [print:0.20mm 100mms Linear Advance] inherits = *0.20mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 @@ -486,7 +594,22 @@ solid_infill_speed = 100 support_material_speed = 60 top_solid_infill_speed = 70 -[print:0.20mm FAST MK3] +# MK3 # +[print:0.20mm QUALITY MK3] +inherits = *0.20mm*; *MK3* +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 +external_perimeter_speed = 25 +infill_acceleration = 1250 +infill_speed = 80 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 80 +top_solid_infill_speed = 40 +fill_pattern = gyroid +fill_density = 15% + +[print:0.20mm SPEED MK3] inherits = *0.20mm*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 @@ -494,14 +617,15 @@ external_perimeter_speed = 35 infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 -perimeter_speed = 45 +perimeter_speed = 60 solid_infill_speed = 200 top_solid_infill_speed = 50 -[print:0.20mm FAST MK3 SOLUBLE FULL] -inherits = 0.20mm FAST MK3; *soluble_support* +# MK3 MMU # +[print:0.20mm SOLUBLE FULL MK3] +inherits = 0.20mm SPEED MK3; *soluble_support* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 -notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder support_material_extruder = 5 support_material_interface_extruder = 5 perimeter_speed = 40 @@ -509,38 +633,44 @@ solid_infill_speed = 40 top_infill_extrusion_width = 0.45 top_solid_infill_speed = 30 -[print:0.20mm FAST MK3 SOLUBLE INTERFACE] -inherits = 0.20mm FAST MK3 SOLUBLE FULL -notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +# MK3 MMU # +[print:0.20mm SOLUBLE INTERFACE MK3] +inherits = 0.20mm SOLUBLE FULL MK3 +notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 +# MK2 # [print:0.20mm NORMAL] inherits = *0.20mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 +# MK2 # [print:0.20mm NORMAL 0.6 nozzle] inherits = *0.20mm*; *0.6nozzle* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 +# MK2 MMU # [print:0.20mm NORMAL SOLUBLE FULL] inherits = *0.20mm*; *soluble_support* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1 external_perimeter_speed = 30 -notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder perimeter_speed = 40 solid_infill_speed = 40 top_solid_infill_speed = 30 +# MK2 MMU # [print:0.20mm NORMAL SOLUBLE INTERFACE] inherits = 0.20mm NORMAL SOLUBLE FULL -notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 support_material_xy_spacing = 80% +# MK3 # [print:0.20mm FAST 0.6 nozzle MK3] inherits = *0.20mm*; *0.6nozzle*; *MK3* bridge_speed = 30 @@ -574,6 +704,7 @@ solid_infill_speed = 60 top_solid_infill_speed = 50 top_solid_layers = 4 +# MK2 # [print:0.35mm FAST] inherits = *0.35mm* bridge_flow_ratio = 0.95 @@ -583,10 +714,12 @@ perimeter_extrusion_width = 0.43 solid_infill_extrusion_width = 0.7 top_infill_extrusion_width = 0.43 +# MK2 # [print:0.35mm FAST 0.6 nozzle] inherits = *0.35mm*; *0.6nozzle* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 +# MK2 MMU # [print:0.35mm FAST sol full 0.6 nozzle] inherits = *0.35mm*; *0.6nozzle*; *soluble_support* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1 @@ -598,6 +731,7 @@ support_material_interface_layers = 3 support_material_xy_spacing = 120% top_infill_extrusion_width = 0.57 +# MK2 MMU # [print:0.35mm FAST sol int 0.6 nozzle] inherits = 0.35mm FAST sol full 0.6 nozzle support_material_extruder = 0 @@ -609,38 +743,45 @@ support_material_xy_spacing = 150% # XXX----- MK2.5 ----XXX # XXXXXXXXXXXXXXXXXXXXXX +# MK2.5 # [print:0.15mm 100mms Linear Advance MK2.5] inherits = 0.15mm 100mms Linear Advance compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 +# MK2.5 # [print:0.15mm OPTIMAL MK2.5] inherits = 0.15mm OPTIMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 +# MK2.5 MMU2 # [print:0.15mm OPTIMAL SOLUBLE FULL MK2.5] inherits = 0.15mm OPTIMAL SOLUBLE FULL support_material_extruder = 5 support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +# MK2.5 MMU2 # [print:0.15mm OPTIMAL SOLUBLE INTERFACE MK2.5] inherits = 0.15mm OPTIMAL SOLUBLE INTERFACE support_material_extruder = 0 support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +# MK2.5 # [print:0.20mm 100mms Linear Advance MK2.5] inherits = 0.20mm 100mms Linear Advance compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 +# MK2.5 # [print:0.20mm NORMAL MK2.5] inherits = 0.20mm NORMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 +# MK2.5 MMU2 # [print:0.20mm NORMAL SOLUBLE FULL MK2.5] inherits = 0.20mm NORMAL SOLUBLE FULL support_material_extruder = 5 @@ -648,6 +789,7 @@ support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 single_extruder_multi_material_priming = 0 +# MK2.5 MMU2 # [print:0.20mm NORMAL SOLUBLE INTERFACE MK2.5] inherits = 0.20mm NORMAL SOLUBLE INTERFACE support_material_extruder = 0 @@ -655,6 +797,7 @@ support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 single_extruder_multi_material_priming = 0 +# MK2.5 # [print:0.35mm FAST MK2.5] inherits = 0.35mm FAST compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 @@ -941,7 +1084,7 @@ first_layer_bed_temperature = 100 first_layer_temperature = 270 temperature = 270 -[filament:Primavalue PVA] +[filament:PrimaSelect PVA+] inherits = *PLA* filament_cost = 108 filament_density = 1.23 @@ -970,6 +1113,11 @@ filament_cooling_final_speed = 50 filament_cooling_initial_speed = 10 filament_cooling_moves = 5 filament_ramming_parameters = "120 110 5.32258 5.45161 5.67742 6 6.48387 7.12903 7.90323 8.70968 9.3871 9.83871 10.0968 10.2258| 0.05 5.30967 0.45 5.50967 0.95 6.1871 1.45 7.39677 1.95 9.05484 2.45 10 2.95 10.3098 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6"; +filament_loading_speed_start = 19 +filament_load_time = 15 +filament_unload_time = 12 +filament_loading_speed = 14 +filament_unloading_speed = 20 [filament:Generic ABS MMU2] inherits = *ABS MMU2* @@ -1016,13 +1164,14 @@ first_layer_temperature = 230 filament_cooling_final_speed = 1 filament_cooling_initial_speed = 2 filament_cooling_moves = 1 -filament_load_time = 12 +filament_load_time = 15 filament_loading_speed = 14 filament_notes = PET filament_ramming_parameters = "120 140 4.70968 4.74194 4.77419 4.80645 4.83871 4.87097 4.90323 5 5.25806 5.67742 6.29032 7.06452 7.83871 8.3871| 0.05 4.72901 0.45 4.73545 0.95 4.83226 1.45 4.88067 1.95 5.05483 2.45 5.93553 2.95 7.53556 3.45 8.6323 3.95 7.6 4.45 7.6 4.95 7.6" -filament_unload_time = 11 +filament_unload_time = 12 filament_unloading_speed = 20 filament_unloading_speed_start = 120 +filament_loading_speed_start = 19 [filament:Generic PET MMU2] inherits = *PET MMU2* @@ -1030,7 +1179,7 @@ inherits = *PET MMU2* [filament:Prusa PET MMU2] inherits = *PET MMU2* -[filament:Prusament PET MMU2] +[filament:Prusament PETG MMU2] inherits = *PET MMU2* [filament:Prusa PLA] @@ -1050,14 +1199,17 @@ filament_notes = "Affordable filament for everyday printing in premium quality m inherits = Prusa PLA compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material temperature = 205 -filament_cooling_final_speed = 1 -filament_cooling_initial_speed = 2 +filament_cooling_final_speed = 2 +filament_cooling_initial_speed = 3 filament_cooling_moves = 1 -filament_load_time = 12 +filament_load_time = 15 filament_loading_speed = 14 -filament_ramming_parameters = "120 110 2.70968 2.93548 3.32258 3.83871 4.58065 5.54839 6.51613 7.35484 7.93548 8.16129| 0.05 2.66451 0.45 3.05805 0.95 4.05807 1.45 5.97742 1.95 7.69999 2.45 8.1936 2.95 11.342 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6" -filament_unload_time = 11 +filament_ramming_parameters = "130 120 2.70968 2.93548 3.32258 3.83871 4.58065 5.54839 6.51613 7.35484 7.93548 8.16129| 0.05 2.66451 0.45 3.05805 0.95 4.05807 1.45 5.97742 1.95 7.69999 2.45 8.1936 2.95 11.342 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6" +filament_unload_time = 12 filament_unloading_speed = 20 +filament_loading_speed_start = 19 +filament_minimal_purge_on_wipe_tower = 15 +filament_unloading_speed_start = 100 [filament:Generic PLA MMU2] inherits = *PLA MMU2* @@ -1140,14 +1292,53 @@ first_layer_temperature = 200 filament_cooling_final_speed = 1 filament_cooling_initial_speed = 2 filament_max_volumetric_speed = 4 -filament_type = PVA +filament_type = PLA filament_cooling_moves = 1 -filament_load_time = 12 +filament_load_time = 15 filament_loading_speed = 14 filament_ramming_parameters = "120 110 1.74194 1.90323 2.16129 2.48387 2.83871 3.25806 3.83871 4.6129 5.41935 5.96774| 0.05 1.69677 0.45 1.96128 0.95 2.63872 1.45 3.46129 1.95 4.99031 2.45 6.12908 2.95 8.30974 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6" -filament_unload_time = 11 +filament_unload_time = 12 filament_unloading_speed = 20 filament_unloading_speed_start = 100 +filament_loading_speed_start = 19 + +[filament:PrimaSelect PVA+ MMU2] +inherits = *common* +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material +bed_temperature = 60 +bridge_fan_speed = 100 +cooling = 0 +disable_fan_first_layers = 1 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #FFFFD7 +filament_cooling_final_speed = 2 +filament_cooling_initial_speed = 4 +filament_cooling_moves = 2 +filament_cost = 25.4 +filament_density = 1.24 +filament_diameter = 1.75 +filament_load_time = 15 +filament_loading_speed = 14 +filament_loading_speed_start = 19 +filament_max_volumetric_speed = 4 +filament_minimal_purge_on_wipe_tower = 5 +filament_notes = PVA +filament_ramming_parameters = "120 110 3.83871 3.90323 3.96774 4.03226 4.09677 4.19355 4.3871 4.83871 5.67742 6.93548 8.54839 10.3226 11.9677 13.2581 14.129 14.5806| 0.05 3.8258 0.45 3.89676 0.95 4.05807 1.45 4.23548 1.95 5.18386 2.45 7.80651 2.95 11.5356 3.45 13.9872 3.95 14.7613 4.45 7.6 4.95 7.6" +filament_soluble = 1 +filament_toolchange_delay = 0 +filament_type = PLA +filament_unload_time = 12 +filament_unloading_speed = 20 +filament_unloading_speed_start = 100 +first_layer_bed_temperature = 60 +first_layer_temperature = 200 +max_fan_speed = 100 +min_fan_speed = 100 +min_print_speed = 15 +slowdown_below_layer_time = 20 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 195 [filament:Verbatim PP] inherits = *common* @@ -1329,33 +1520,66 @@ inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 40 +# v2 + +[sla_material:3DM-ABS 0.05] +inherits = *common 0.05* +exposure_time = 9 +initial_exposure_time = 35 + +[sla_material:3DM-DENT 0.05] +inherits = *common 0.05* +exposure_time = 7 +initial_exposure_time = 45 + +[sla_material:3DM-HR Green 0.05] +inherits = *common 0.05* +exposure_time = 15 +initial_exposure_time = 40 + +[sla_material:3DM-HR Red Wine 0.05] +inherits = *common 0.05* +exposure_time = 9 +initial_exposure_time = 35 + +[sla_material:3DM-XPRO White 0.05] +inherits = *common 0.05* +exposure_time = 9 +initial_exposure_time = 35 + +[sla_material:FTD Ash Grey 0.05] +inherits = *common 0.05* +exposure_time = 9 +initial_exposure_time = 40 + +[sla_material:Jamg He LOC-19 Super Low Odor Skin 0.05] +inherits = *common 0.05* +exposure_time = 7.5 +initial_exposure_time = 40 + +[sla_material:Jamg He LOC-20 Super Low Odor White 0.05] +inherits = *common 0.05* +exposure_time = 6.5 +initial_exposure_time = 40 + +[sla_material:Jamg He LOC-60 Super Low Odor Grey 0.05] +inherits = *common 0.05* +exposure_time = 6.5 +initial_exposure_time = 40 + ########### Materials 0.035 -## [sla_material:Jamg He Transparent Clear 0.035] -## inherits = *common 0.035* - -## [sla_material:Jamg He Transparent Green 0.035] -## inherits = *common 0.035* - -## [sla_material:Jamg He Transparent Orange 0.035] -## inherits = *common 0.035* - -## [sla_material:Jamg He Transparent Red 0.035] -## inherits = *common 0.035* +[sla_material:Jamg He PJHC-30 Orange 0.035] +inherits = *common 0.035* +exposure_time = 9 +initial_exposure_time = 35 ########### Materials 0.1 -## [sla_material:Jamg He Transparent Clear 0.1] -## inherits = *common 0.1* - -## [sla_material:Jamg He Transparent Green 0.1] -## inherits = *common 0.1* - -## [sla_material:Jamg He Transparent Orange 0.1] -## inherits = *common 0.1* - -## [sla_material:Jamg He Transparent Red 0.1] -## inherits = *common 0.1* +[sla_material:Jamg He PJHC-30 Orange 0.1] +inherits = *common 0.1* +exposure_time = 10 +initial_exposure_time = 45 [printer:*common*] printer_technology = FFF @@ -1462,10 +1686,10 @@ default_print_profile = 0.15mm OPTIMAL # XXX--- MK2 ---XXX # XXXXXXXXXXXXXXXXX -[printer:Original Prusa i3 MK2] +[printer:Original Prusa i3 MK2S] inherits = *common* -[printer:Original Prusa i3 MK2 0.25 nozzle] +[printer:Original Prusa i3 MK2S 0.25 nozzle] inherits = *common* max_layer_height = 0.15 min_layer_height = 0.05 @@ -1476,7 +1700,7 @@ variable_layer_height = 1 printer_variant = 0.25 default_print_profile = 0.10mm DETAIL 0.25 nozzle -[printer:Original Prusa i3 MK2 0.6 nozzle] +[printer:Original Prusa i3 MK2S 0.6 nozzle] inherits = *common* max_layer_height = 0.35 min_layer_height = 0.1 @@ -1488,12 +1712,12 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle # XXX--- MK2MM ---XXX # XXXXXXXXXXXXXXXXXXX -[printer:Original Prusa i3 MK2 MMU1 Single] +[printer:Original Prusa i3 MK2S MMU1 Single] inherits = *mm-single* max_layer_height = 0.25 min_layer_height = 0.07 -[printer:Original Prusa i3 MK2 MMU1 Single 0.6 nozzle] +[printer:Original Prusa i3 MK2S MMU1 Single 0.6 nozzle] inherits = *mm-single* nozzle_diameter = 0.6 printer_variant = 0.6 @@ -1501,13 +1725,13 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle max_layer_height = 0.35 min_layer_height = 0.1 -[printer:Original Prusa i3 MK2 MMU1] +[printer:Original Prusa i3 MK2S MMU1] inherits = *mm-multi* nozzle_diameter = 0.4,0.4,0.4,0.4 max_layer_height = 0.25 min_layer_height = 0.07 -[printer:Original Prusa i3 MK2 MMU1 0.6 nozzle] +[printer:Original Prusa i3 MK2S MMU1 0.6 nozzle] inherits = *mm-multi* nozzle_diameter = 0.6,0.6,0.6,0.6 printer_variant = 0.6 @@ -1520,7 +1744,19 @@ min_layer_height = 0.1 # XXXXXXXXXXXXXXXXXXX [printer:Original Prusa i3 MK2.5] -inherits = Original Prusa i3 MK2 +inherits = Original Prusa i3 MK2S +printer_model = MK2.5 +remaining_times = 1 +start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 + +[printer:Original Prusa i3 MK2.5 0.25 nozzle] +inherits = Original Prusa i3 MK2S 0.25 nozzle +printer_model = MK2.5 +remaining_times = 1 +start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 + +[printer:Original Prusa i3 MK2.5 0.6 nozzle] +inherits = Original Prusa i3 MK2S 0.6 nozzle printer_model = MK2.5 remaining_times = 1 start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 @@ -1552,7 +1788,7 @@ machine_min_travel_rate = 0 default_print_profile = 0.15mm OPTIMAL MK2.5 default_filament_profile = Prusament PLA printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n -start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK2.5 MMU2] @@ -1586,20 +1822,85 @@ single_extruder_multi_material = 1 # to be defined explicitely. nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n -[printer:Original Prusa i3 MK2.5 0.25 nozzle] -inherits = Original Prusa i3 MK2 0.25 nozzle -printer_model = MK2.5 -remaining_times = 1 -start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +[printer:Original Prusa i3 MK2.5S] +inherits = Original Prusa i3 MK2.5 +printer_model = MK2.5S -[printer:Original Prusa i3 MK2.5 0.6 nozzle] -inherits = Original Prusa i3 MK2 0.6 nozzle -printer_model = MK2.5 +[printer:Original Prusa i3 MK2.5S 0.25 nozzle] +inherits = Original Prusa i3 MK2.5 0.25 nozzle +printer_model = MK2.5S + +[printer:Original Prusa i3 MK2.5S 0.6 nozzle] +inherits = Original Prusa i3 MK2.5 0.6 nozzle +printer_model = MK2.5S + +[printer:Original Prusa i3 MK2.5S MMU2S Single] +inherits = Original Prusa i3 MK2.5; *mm2s* +printer_model = MK2.5SMMU2S +single_extruder_multi_material = 0 +max_print_height = 200 remaining_times = 1 -start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +silent_mode = 0 +retract_lift_below = 199 +machine_max_acceleration_e = 10000 +machine_max_acceleration_extruding = 2000 +machine_max_acceleration_retracting = 1500 +machine_max_acceleration_x = 9000 +machine_max_acceleration_y = 9000 +machine_max_acceleration_z = 500 +machine_max_feedrate_e = 120 +machine_max_feedrate_x = 500 +machine_max_feedrate_y = 500 +machine_max_feedrate_z = 12 +machine_max_jerk_e = 2.5 +machine_max_jerk_x = 10 +machine_max_jerk_y = 10 +machine_max_jerk_z = 0.2 +machine_min_extruding_rate = 0 +machine_min_travel_rate = 0 +default_print_profile = 0.15mm OPTIMAL MK2.5 +default_filament_profile = Prusament PLA +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n +start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors + +[printer:Original Prusa i3 MK2.5S MMU2S] +inherits = Original Prusa i3 MK2.5; *mm2s* +printer_model = MK2.5SMMU2S +max_print_height = 200 +remaining_times = 1 +silent_mode = 0 +retract_lift_below = 199 +machine_max_acceleration_e = 10000 +machine_max_acceleration_extruding = 2000 +machine_max_acceleration_retracting = 1500 +machine_max_acceleration_x = 9000 +machine_max_acceleration_y = 9000 +machine_max_acceleration_z = 500 +machine_max_feedrate_e = 120 +machine_max_feedrate_x = 500 +machine_max_feedrate_y = 500 +machine_max_feedrate_z = 12 +machine_max_jerk_e = 2.5 +machine_max_jerk_x = 10 +machine_max_jerk_y = 10 +machine_max_jerk_z = 0.2 +machine_min_extruding_rate = 0 +machine_min_travel_rate = 0 +default_print_profile = 0.15mm OPTIMAL MK2.5 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n +single_extruder_multi_material = 1 +# The 5x nozzle diameter defines the number of extruders. Other extruder parameters +# (for example the retract values) are duplicaed from the first value, so they do not need +# to be defined explicitely. +nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 +extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F +start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n + # XXXXXXXXXXXXXXXXX # XXX--- MK3 ---XXX @@ -1629,9 +1930,9 @@ remaining_times = 1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 max_print_height = 210 -start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +start_gcode = M115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} printer_model = MK3 -default_print_profile = 0.15mm OPTIMAL MK3 +default_print_profile = 0.15mm QUALITY MK3 [printer:Original Prusa i3 MK3 0.25 nozzle] inherits = Original Prusa i3 MK3 @@ -1649,6 +1950,18 @@ min_layer_height = 0.1 printer_variant = 0.6 default_print_profile = 0.15mm OPTIMAL 0.6 nozzle MK3 +[printer:Original Prusa i3 MK3S] +inherits = Original Prusa i3 MK3 +printer_model = MK3S + +[printer:Original Prusa i3 MK3S 0.25 nozzle] +inherits = Original Prusa i3 MK3 0.25 nozzle +printer_model = MK3S + +[printer:Original Prusa i3 MK3S 0.6 nozzle] +inherits = Original Prusa i3 MK3 0.6 nozzle +printer_model = MK3S + [printer:*mm2*] inherits = Original Prusa i3 MK3 single_extruder_multi_material = 1 @@ -1658,7 +1971,19 @@ parking_pos_retraction = 85 retract_length_toolchange = 3 extra_loading_move = -13 printer_model = MK3MMU2 -default_print_profile = 0.15mm OPTIMAL MK3 +default_print_profile = 0.15mm QUALITY MK3 +default_filament_profile = Prusament PLA MMU2 + +[printer:*mm2s*] +inherits = Original Prusa i3 MK3 +single_extruder_multi_material = 1 +cooling_tube_length = 20 +cooling_tube_retraction = 40 +parking_pos_retraction = 85 +retract_length_toolchange = 3 +extra_loading_move = -25 +printer_model = MK3SMMU2S +default_print_profile = 0.15mm QUALITY MK3 default_filament_profile = Prusament PLA MMU2 [printer:Original Prusa i3 MK3 MMU2 Single] @@ -1679,6 +2004,21 @@ extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n +[printer:Original Prusa i3 MK3S MMU2S Single] +inherits = *mm2s* +single_extruder_multi_material = 0 +default_filament_profile = Prusament PLA +start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors + +[printer:Original Prusa i3 MK3S MMU2S] +inherits = *mm2s* +machine_max_acceleration_e = 8000,8000 +nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 +extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F +start_gcode = M107\nM115 U3.5.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n + [printer:Original Prusa SL1] printer_technology = SLA printer_model = SL1 diff --git a/resources/shaders/printbed.fs b/resources/shaders/printbed.fs new file mode 100644 index 000000000..be14347c2 --- /dev/null +++ b/resources/shaders/printbed.fs @@ -0,0 +1,20 @@ +#version 110 + +const vec3 back_color_dark = vec3(0.235, 0.235, 0.235); +const vec3 back_color_light = vec3(0.365, 0.365, 0.365); + +uniform sampler2D texture; +uniform bool transparent_background; + +varying vec2 tex_coords; + +void main() +{ + // calculates radial gradient + vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coords.xy) - vec2(0.5))))); + + vec4 fore_color = texture2D(texture, tex_coords); + + // blends foreground with background + gl_FragColor = vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0); +} \ No newline at end of file diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs new file mode 100644 index 000000000..ac4763782 --- /dev/null +++ b/resources/shaders/printbed.vs @@ -0,0 +1,12 @@ +#version 110 + +attribute vec4 v_position; +attribute vec2 v_tex_coords; + +varying vec2 tex_coords; + +void main() +{ + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position; + tex_coords = v_tex_coords; +} diff --git a/sandboxes/slabasebed/CMakeLists.txt b/sandboxes/slabasebed/CMakeLists.txt index bff5ca588..9d731a133 100644 --- a/sandboxes/slabasebed/CMakeLists.txt +++ b/sandboxes/slabasebed/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(slabasebed EXCLUDE_FROM_ALL slabasebed.cpp) -target_link_libraries(slabasebed libslic3r) \ No newline at end of file +target_link_libraries(slabasebed libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/sandboxes/slabasebed/slabasebed.cpp b/sandboxes/slabasebed/slabasebed.cpp index 9804ea3c9..323741609 100644 --- a/sandboxes/slabasebed/slabasebed.cpp +++ b/sandboxes/slabasebed/slabasebed.cpp @@ -1,15 +1,29 @@ #include +#include #include #include #include #include +#include #include const std::string USAGE_STR = { "Usage: slabasebed stlfilename.stl" }; +namespace Slic3r { namespace sla { + +Contour3D convert(const Polygons& triangles, coord_t z, bool dir); +Contour3D walls(const Polygon& floor_plate, const Polygon& ceiling, + double floor_z_mm, double ceiling_z_mm, + double offset_difference_mm, ThrowOnCancel thr); + +void offset(ExPolygon& sh, coord_t distance); + +} +} + int main(const int argc, const char *argv[]) { using namespace Slic3r; using std::cout; using std::endl; @@ -26,18 +40,43 @@ int main(const int argc, const char *argv[]) { model.align_to_origin(); ExPolygons ground_slice; - TriangleMesh basepool; + sla::Contour3D mesh; +// TriangleMesh basepool; sla::base_plate(model, ground_slice, 0.1f); + if(ground_slice.empty()) return EXIT_FAILURE; + + ExPolygon bottom_plate = ground_slice.front(); + ExPolygon top_plate = bottom_plate; + sla::offset(top_plate, coord_t(3.0/SCALING_FACTOR)); + sla::offset(bottom_plate, coord_t(1.0/SCALING_FACTOR)); + bench.start(); - sla::create_base_pool(ground_slice, basepool); + + Polygons top_plate_triangles, bottom_plate_triangles; + top_plate.triangulate_p2t(&top_plate_triangles); + bottom_plate.triangulate_p2t(&bottom_plate_triangles); + + auto top_plate_mesh = sla::convert(top_plate_triangles, coord_t(3.0/SCALING_FACTOR), false); + auto bottom_plate_mesh = sla::convert(bottom_plate_triangles, 0, true); + + mesh.merge(bottom_plate_mesh); + mesh.merge(top_plate_mesh); + + sla::Contour3D w = sla::walls(bottom_plate.contour, top_plate.contour, 0, 3, 2.0, [](){}); + + mesh.merge(w); +// sla::create_base_pool(ground_slice, basepool); bench.stop(); cout << "Base pool creation time: " << std::setprecision(10) << bench.getElapsedSec() << " seconds." << endl; - basepool.write_ascii("out.stl"); +// basepool.write_ascii("out.stl"); + + std::fstream outstream("out.obj", std::fstream::out); + mesh.to_obj(outstream); return EXIT_SUCCESS; } diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index ad0835ec0..0e9b9e6d4 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 3.0) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) add_definitions(-D_BSD_SOURCE -D_DEFAULT_SOURCE) # To enable various useful macros and functions on Unices remove_definitions(-D_UNICODE -DUNICODE) @@ -68,18 +70,31 @@ set(AVRDUDE_SOURCES ) if (MSVC) set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES} + windows/utf8.c windows/unistd.cpp windows/getopt.c ) endif() -add_library(avrdude STATIC ${AVRDUDE_SOURCES}) -set(STANDALONE_SOURCES - main-standalone.c +add_executable(avrdude-conf-gen conf-generate.cpp) + +# Config file embedding +add_custom_command( + DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h + COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf > avrdude-slic3r.conf.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -add_executable(avrdude-slic3r ${STANDALONE_SOURCES}) + +add_custom_target(gen_conf_h + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h +) + +add_library(avrdude STATIC ${AVRDUDE_SOURCES}) +add_dependencies(avrdude gen_conf_h) + +add_executable(avrdude-slic3r main-standalone.cpp) target_link_libraries(avrdude-slic3r avrdude) -set_target_properties(avrdude-slic3r PROPERTIES EXCLUDE_FROM_ALL TRUE) if (WIN32) target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1) diff --git a/src/avrdude/ac_cfg.h b/src/avrdude/ac_cfg.h index 2461bf307..41d648bf1 100644 --- a/src/avrdude/ac_cfg.h +++ b/src/avrdude/ac_cfg.h @@ -169,22 +169,22 @@ #define LT_OBJDIR ".libs/" /* Name of package */ -#define PACKAGE "avrdude" +#define PACKAGE "avrdude-slic3r" /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "avrdude-dev@nongnu.org" +#define PACKAGE_BUGREPORT "https://github.com/prusa3d/Slic3r/issues" /* Define to the full name of this package. */ -#define PACKAGE_NAME "avrdude" +#define PACKAGE_NAME "avrdude-slic3r" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "avrdude 6.3-20160220" /* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "avrdude" +#define PACKAGE_TARNAME "avrdude-slic3r" /* Define to the home page for this package. */ -#define PACKAGE_URL "" +#define PACKAGE_URL "https://github.com/prusa3d/Slic3r" /* Define to the version of this package. */ #define PACKAGE_VERSION "6.3-20160220" diff --git a/src/avrdude/arduino.c b/src/avrdude/arduino.c index 5a9cb465e..53e5ed822 100644 --- a/src/avrdude/arduino.c +++ b/src/avrdude/arduino.c @@ -158,8 +158,10 @@ static int arduino_open(PROGRAMMER * pgm, char * port) return -1; } - if (stk500_getsync(pgm) < 0) + if (stk500_getsync(pgm) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } diff --git a/src/avrdude/avrdude-slic3r.conf b/src/avrdude/avrdude-slic3r.conf new file mode 100644 index 000000000..861c4fb4d --- /dev/null +++ b/src/avrdude/avrdude-slic3r.conf @@ -0,0 +1,424 @@ + +# +# This is a basic minimal config file embedded into the avrdude-slic3r binary +# so that it can work in a standalone manner. +# +# Only the bits useful for Prusa3D devices were copied over from avrdude.conf +# If needed, more configuration can still be loaded into avrdude-slic3r +# via the -C command-line option. +# + + +programmer + id = "wiring"; + desc = "Wiring"; + type = "wiring"; + connection_type = serial; +; + +programmer + id = "arduino"; + desc = "Arduino"; + type = "arduino"; + connection_type = serial; +; + +programmer + id = "avr109"; + desc = "Atmel AppNote AVR109 Boot Loader"; + type = "butterfly"; + connection_type = serial; +; + + +#------------------------------------------------------------ +# ATmega2560 +#------------------------------------------------------------ + +part + id = "m2560"; + desc = "ATmega2560"; + signature = 0x1e 0x98 0x01; + has_jtag = yes; + stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + ocdrev = 4; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 262144; + page_size = 256; + num_pages = 1024; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + load_ext_addr = " 0 1 0 0 1 1 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 a16", + " 0 0 0 0 0 0 0 0"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + + + +#------------------------------------------------------------ +# ATmega32u4 +#------------------------------------------------------------ + +part + id = "m32u4"; + desc = "ATmega32U4"; + signature = 0x1e 0x95 0x87; + usbpid = 0x2ff4; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + ocdrev = 3; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + diff --git a/src/avrdude/avrdude-slic3r.conf.h b/src/avrdude/avrdude-slic3r.conf.h new file mode 100644 index 000000000..7cc901336 --- /dev/null +++ b/src/avrdude/avrdude-slic3r.conf.h @@ -0,0 +1,1188 @@ +/* WARN: This file is auto-generated from `avrdude-slic3r.conf` */ +unsigned char avrdude_slic3r_conf[] = { + 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x6d, 0x69, 0x6e, + 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, + 0x66, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x63, 0x33, + 0x72, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x73, + 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, + 0x6e, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, + 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x6d, + 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x4f, + 0x6e, 0x6c, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x74, 0x73, + 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x50, 0x72, 0x75, 0x73, 0x61, 0x33, 0x44, 0x20, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x70, + 0x69, 0x65, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x66, 0x72, 0x6f, + 0x6d, 0x20, 0x61, 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x0a, 0x23, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x65, 0x65, 0x64, + 0x65, 0x64, 0x2c, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, + 0x61, 0x6e, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, + 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, + 0x61, 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x63, + 0x33, 0x72, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x61, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x2d, 0x43, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, + 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x0a, 0x23, 0x0a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x77, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3b, 0x0a, + 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x57, + 0x69, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x77, 0x69, 0x72, 0x69, 0x6e, + 0x67, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, + 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, + 0x63, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x72, 0x64, 0x75, 0x69, 0x6e, + 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x22, 0x3b, + 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x61, 0x76, 0x72, 0x31, 0x30, 0x39, + 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, 0x20, 0x3d, + 0x20, 0x22, 0x41, 0x74, 0x6d, 0x65, 0x6c, 0x20, 0x41, 0x70, 0x70, 0x4e, + 0x6f, 0x74, 0x65, 0x20, 0x41, 0x56, 0x52, 0x31, 0x30, 0x39, 0x20, 0x42, + 0x6f, 0x6f, 0x74, 0x20, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x22, 0x3b, + 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x22, + 0x62, 0x75, 0x74, 0x74, 0x65, 0x72, 0x66, 0x6c, 0x79, 0x22, 0x3b, 0x0a, + 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, + 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x32, 0x35, 0x36, 0x30, 0x0a, 0x23, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x6d, 0x32, 0x35, 0x36, 0x30, + 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x32, 0x35, 0x36, + 0x30, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x30, 0x78, 0x31, 0x65, 0x20, 0x30, 0x78, 0x39, 0x38, + 0x20, 0x30, 0x78, 0x30, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, + 0x61, 0x73, 0x5f, 0x6a, 0x74, 0x61, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x73, 0x74, 0x6b, 0x35, 0x30, 0x30, 0x5f, 0x64, 0x65, + 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, + 0x42, 0x32, 0x3b, 0x0a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x61, 0x76, 0x72, + 0x39, 0x31, 0x30, 0x5f, 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x33, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x6c, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x30, 0x78, 0x44, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x62, 0x73, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x41, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x70, 0x67, 0x6d, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, + 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, + 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x22, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, + 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6d, 0x64, 0x65, 0x78, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x62, 0x79, 0x74, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, + 0x6c, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, + 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x45, 0x2c, + 0x20, 0x30, 0x78, 0x31, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x46, 0x2c, + 0x20, 0x30, 0x78, 0x31, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x45, 0x2c, + 0x20, 0x30, 0x78, 0x33, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x46, 0x2c, + 0x20, 0x30, 0x78, 0x33, 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x30, 0x78, 0x34, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x35, + 0x45, 0x2c, 0x20, 0x30, 0x78, 0x34, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x35, + 0x46, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x37, + 0x45, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x37, + 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, + 0x78, 0x36, 0x36, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x36, 0x2c, 0x20, 0x30, + 0x78, 0x36, 0x37, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x37, 0x2c, 0x20, 0x30, + 0x78, 0x36, 0x41, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x41, 0x2c, 0x20, 0x30, + 0x78, 0x36, 0x42, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x42, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x42, 0x45, 0x2c, + 0x20, 0x30, 0x78, 0x46, 0x44, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, + 0x20, 0x30, 0x78, 0x30, 0x31, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, + 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, + 0x20, 0x30, 0x78, 0x30, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, + 0x76, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x6d, 0x6f, + 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x61, 0x74, 0x63, 0x68, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x76, 0x74, + 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x6f, 0x66, 0x66, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x6d, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, + 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x68, 0x76, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x74, 0x61, 0x62, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, + 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x65, + 0x72, 0x61, 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x68, 0x69, 0x70, 0x65, 0x72, 0x61, 0x73, 0x65, 0x70, 0x6f, 0x6c, + 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x31, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x66, 0x75, 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, 0x73, + 0x65, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x75, 0x6c, + 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x64, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x30, 0x78, 0x33, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, + 0x6d, 0x63, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x37, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x61, 0x6d, 0x70, 0x7a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x33, 0x62, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x66, 0x75, 0x6c, 0x6c, 0x70, + 0x61, 0x67, 0x65, 0x62, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6f, 0x63, 0x64, 0x72, 0x65, 0x76, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x34, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, + 0x20, 0x22, 0x65, 0x65, 0x70, 0x72, 0x6f, 0x6d, 0x22, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x6e, 0x6f, 0x3b, 0x20, 0x2f, 0x2a, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x22, 0x6e, 0x6f, 0x22, 0x20, 0x2a, + 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x38, 0x3b, 0x20, 0x20, 0x2f, 0x2a, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, + 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x20, + 0x2a, 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x34, 0x30, 0x39, 0x36, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, + 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, + 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, + 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, + 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, + 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, + 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, + 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, + 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, + 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, + 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, + 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, + 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x20, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, + 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, + 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, 0x3d, 0x20, 0x22, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, + 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, + 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x70, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, + 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, + 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, + 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, + 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x31, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x32, + 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, + 0x22, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, + 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x36, 0x32, 0x31, 0x34, 0x34, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x67, 0x65, + 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, + 0x32, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, + 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, + 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, + 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x31, 0x35, 0x20, 0x61, + 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, + 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, + 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, + 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, + 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, + 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, + 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x61, 0x31, 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, + 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, + 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, + 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, + 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, + 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, + 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, + 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, + 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, + 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, + 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x68, 0x69, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, + 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, + 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, + 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, + 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, + 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x70, 0x61, 0x67, + 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, + 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x61, 0x31, 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, + 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, + 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, + 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, + 0x64, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x36, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, + 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x31, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, + 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, + 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x20, 0x22, 0x6c, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, + 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, + 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, + 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x68, 0x66, 0x75, + 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, + 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, + 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, + 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, + 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, + 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, + 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, + 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x20, 0x22, 0x65, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x20, 0x78, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, + 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, + 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x6c, 0x6f, 0x63, + 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, + 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, + 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, + 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x31, 0x20, + 0x31, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, + 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, + 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, + 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, + 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x20, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, + 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x20, 0x61, 0x30, 0x20, 0x20, + 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, + 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, + 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x20, + 0x20, 0x3b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, + 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x33, 0x32, 0x75, 0x34, 0x0a, 0x23, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x6d, 0x33, 0x32, 0x75, 0x34, + 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x22, 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x33, 0x32, 0x55, + 0x34, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x30, 0x78, 0x31, 0x65, 0x20, 0x30, 0x78, 0x39, 0x35, + 0x20, 0x30, 0x78, 0x38, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, + 0x73, 0x62, 0x70, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x32, 0x66, 0x66, 0x34, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x61, 0x73, 0x5f, 0x6a, 0x74, + 0x61, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x74, 0x6b, 0x35, 0x30, 0x30, 0x5f, 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, + 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x42, 0x32, 0x3b, 0x0a, + 0x23, 0x20, 0x20, 0x20, 0x20, 0x61, 0x76, 0x72, 0x39, 0x31, 0x30, 0x5f, + 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x30, 0x78, 0x34, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, + 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x6c, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, + 0x44, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x73, 0x32, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x30, 0x78, 0x41, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, + 0x67, 0x6d, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x65, + 0x72, 0x61, 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, + 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x32, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, + 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6d, 0x64, + 0x65, 0x78, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x32, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x79, 0x6e, + 0x63, 0x68, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x79, 0x74, + 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x33, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x70, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, + 0x6c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x70, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x31, + 0x45, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x31, + 0x46, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x33, + 0x45, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x33, + 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, + 0x78, 0x34, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x45, 0x2c, 0x20, 0x30, + 0x78, 0x34, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x46, 0x2c, 0x20, 0x30, + 0x78, 0x36, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x45, 0x2c, 0x20, 0x30, + 0x78, 0x36, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x46, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x36, 0x36, 0x2c, + 0x20, 0x30, 0x78, 0x37, 0x36, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x37, 0x2c, + 0x20, 0x30, 0x78, 0x37, 0x37, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x41, 0x2c, + 0x20, 0x30, 0x78, 0x37, 0x41, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x42, 0x2c, + 0x20, 0x30, 0x78, 0x37, 0x42, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x30, 0x78, 0x42, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x46, + 0x44, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, + 0x31, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, + 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x76, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x6d, 0x6f, 0x64, 0x65, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x61, 0x74, 0x63, 0x68, + 0x63, 0x79, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x76, 0x74, 0x67, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x6f, 0x66, + 0x66, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x6d, 0x73, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x76, 0x6c, + 0x65, 0x61, 0x76, 0x65, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x65, 0x72, 0x61, 0x73, 0x65, + 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, + 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, + 0x65, 0x72, 0x61, 0x73, 0x65, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, + 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, 0x73, 0x65, 0x70, 0x6f, 0x6c, + 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x35, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x6f, 0x63, 0x6b, + 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, + 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x64, + 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x33, 0x31, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x6d, 0x63, 0x72, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x37, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x61, 0x6d, 0x70, 0x7a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x30, 0x78, 0x33, 0x62, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x66, 0x75, 0x6c, 0x6c, 0x70, 0x61, 0x67, 0x65, 0x62, + 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x3d, 0x20, 0x6e, + 0x6f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x63, 0x64, 0x72, + 0x65, 0x76, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x65, 0x65, + 0x70, 0x72, 0x6f, 0x6d, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x3b, 0x20, + 0x2f, 0x2a, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x22, 0x6e, 0x6f, 0x22, 0x20, 0x2a, 0x2f, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x34, 0x3b, 0x20, 0x20, 0x2f, 0x2a, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, + 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x2a, 0x2f, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x31, 0x30, 0x32, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, + 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, + 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x30, + 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, + 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, + 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, + 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, + 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, + 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, + 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, + 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x20, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, + 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, + 0x5f, 0x6c, 0x6f, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, + 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, + 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x70, 0x61, + 0x67, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, + 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, + 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, + 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, + 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x69, 0x7a, 0x65, 0x20, + 0x3d, 0x20, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, + 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x66, 0x6c, 0x61, + 0x73, 0x68, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x33, 0x32, 0x37, 0x36, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, + 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x32, + 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, + 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, + 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, + 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, + 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, + 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, + 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, + 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, + 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, + 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, + 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, + 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, + 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, + 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, + 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, + 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, + 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, + 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, + 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, + 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, + 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, + 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, + 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, + 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, + 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, + 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, + 0x69, 0x74, 0x65, 0x70, 0x61, 0x67, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, + 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x31, + 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, + 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, + 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, + 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, + 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, + 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, + 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x32, 0x38, 0x3b, 0x0a, + 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, + 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x20, 0x22, 0x6c, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, + 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, + 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, + 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, + 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x68, 0x66, + 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, + 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, + 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, + 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, + 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, + 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, + 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x20, 0x22, 0x65, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, + 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, + 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, + 0x31, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, + 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, + 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, + 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x6c, 0x6f, + 0x63, 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, + 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, + 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, + 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, + 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, + 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x31, + 0x20, 0x31, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, + 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, + 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, + 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x63, 0x61, 0x6c, 0x69, 0x62, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x20, + 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, + 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, + 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x30, 0x20, + 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, + 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, + 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, + 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, + 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, + 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x20, 0x61, 0x30, 0x20, + 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, + 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, + 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, + 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x0a, + 0, 0 +}; +size_t avrdude_slic3r_conf_size = 14178; +size_t avrdude_slic3r_conf_size_yy = 14180; diff --git a/src/avrdude/avrdude-slic3r.cpp b/src/avrdude/avrdude-slic3r.cpp index 3037f5284..0140d93ed 100644 --- a/src/avrdude/avrdude-slic3r.cpp +++ b/src/avrdude/avrdude-slic3r.cpp @@ -42,7 +42,6 @@ static void avrdude_oom_handler(const char *context, void *user_p) struct AvrDude::priv { - std::string sys_config; std::deque> args; bool cancelled = false; int exit_code = 0; @@ -54,8 +53,6 @@ struct AvrDude::priv std::thread avrdude_thread; - priv(std::string &&sys_config) : sys_config(sys_config) {} - void set_handlers(); void unset_handlers(); int run_one(const std::vector &args); @@ -96,14 +93,21 @@ void AvrDude::priv::unset_handlers() int AvrDude::priv::run_one(const std::vector &args) { - std::vector c_args {{ const_cast(PACKAGE_NAME) }}; + std::vector c_args {{ const_cast(PACKAGE) }}; + std::string command_line { PACKAGE }; + for (const auto &arg : args) { c_args.push_back(const_cast(arg.data())); + command_line.push_back(' '); + command_line.append(arg); } + command_line.push_back('\n'); HandlerGuard guard(*this); - const auto res = ::avrdude_main(static_cast(c_args.size()), c_args.data(), sys_config.c_str()); + message_fn(command_line.c_str(), command_line.size()); + + const auto res = ::avrdude_main(static_cast(c_args.size()), c_args.data()); return res; } @@ -123,7 +127,7 @@ int AvrDude::priv::run() { // Public -AvrDude::AvrDude(std::string sys_config) : p(new priv(std::move(sys_config))) {} +AvrDude::AvrDude() : p(new priv()) {} AvrDude::AvrDude(AvrDude &&other) : p(std::move(other.p)) {} diff --git a/src/avrdude/avrdude-slic3r.hpp b/src/avrdude/avrdude-slic3r.hpp index 754e1e345..99be6a828 100644 --- a/src/avrdude/avrdude-slic3r.hpp +++ b/src/avrdude/avrdude-slic3r.hpp @@ -22,8 +22,7 @@ public: typedef std::function ProgressFn; typedef std::function CompleteFn; - // Main c-tor, sys_config is the location of avrdude's main configuration file - AvrDude(std::string sys_config); + AvrDude(); AvrDude(AvrDude &&); AvrDude(const AvrDude &) = delete; AvrDude &operator=(AvrDude &&) = delete; diff --git a/src/avrdude/avrdude.h b/src/avrdude/avrdude.h index f4c92a75d..ff464f46f 100644 --- a/src/avrdude/avrdude.h +++ b/src/avrdude/avrdude.h @@ -55,7 +55,7 @@ void avrdude_cancel(); #define MSG_TRACE (4) /* displayed with -vvvv, show trace commuication */ #define MSG_TRACE2 (5) /* displayed with -vvvvv */ -int avrdude_main(int argc, char * argv [], const char *sys_config); +int avrdude_main(int argc, char * argv []); #if defined(WIN32NATIVE) diff --git a/src/avrdude/conf-generate.cpp b/src/avrdude/conf-generate.cpp new file mode 100644 index 000000000..f2761ba22 --- /dev/null +++ b/src/avrdude/conf-generate.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include + + +int main(int argc, char const *argv[]) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + const char* filename = argv[1]; + const char* symbol = argv[2]; + + size_t size = 0; + std::fstream file(filename); + if (!file.good()) { + std::cerr << "Cannot read file: " << filename << std::endl; + } + + std::cout << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl; + std::cout << "unsigned char " << symbol << "[] = {"; + + char c; + std::cout << std::hex; + std::cout.fill('0'); + for (file.get(c); !file.eof(); size++, file.get(c)) { + if (size % 12 == 0) { std::cout << "\n "; } + std::cout << "0x" << std::setw(2) << (unsigned)c << ", "; + } + + std::cout << "\n 0, 0\n};\n"; + + std::cout << std::dec; + std::cout << "size_t " << symbol << "_size = " << size << ";" << std::endl; + std::cout << "size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl; + + return 0; +} diff --git a/src/avrdude/config.c b/src/avrdude/config.c index 08193cfc5..1c0ff5525 100644 --- a/src/avrdude/config.c +++ b/src/avrdude/config.c @@ -32,6 +32,8 @@ #include "config_gram.h" +#include "avrdude-slic3r.conf.h" // Embedded config file + char default_programmer[MAX_STR_CONST]; char default_parallel[PATH_MAX]; char default_serial[PATH_MAX]; @@ -325,7 +327,7 @@ int read_config(const char * file) FILE * f; int r; - f = fopen(file, "r"); + f = fopen_utf8(file, "r"); if (f == NULL) { avrdude_message(MSG_INFO, "%s: can't open config file \"%s\": %s\n", progname, file, strerror(errno)); @@ -347,3 +349,33 @@ int read_config(const char * file) return r; } + +typedef struct yy_buffer_state *YY_BUFFER_STATE; +extern YY_BUFFER_STATE yy_scan_bytes(char *base, size_t size); +extern void yy_delete_buffer(YY_BUFFER_STATE b); + +int read_config_builtin() +{ + int r; + + lineno = 1; + infile = "(builtin)"; + + // Note: Can't use yy_scan_buffer, it's buggy (?), leads to fread from a null FILE* + // and so unfortunatelly we have to use the copying variant here + YY_BUFFER_STATE buffer = yy_scan_bytes(avrdude_slic3r_conf, avrdude_slic3r_conf_size); + if (buffer == NULL) { + avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname); + return -1; + } + + r = yyparse(); + yy_delete_buffer(buffer); + +#ifdef HAVE_YYLEX_DESTROY + /* reset lexer and free any allocated memory */ + yylex_destroy(); +#endif + + return r; +} diff --git a/src/avrdude/fileio.c b/src/avrdude/fileio.c index 708159295..7803497a0 100644 --- a/src/avrdude/fileio.c +++ b/src/avrdude/fileio.c @@ -40,6 +40,9 @@ #include "avrdude.h" #include "libavrdude.h" +#if defined(WIN32NATIVE) +#include "windows/utf8.h" +#endif #define IHEX_MAXDATA 256 @@ -102,21 +105,25 @@ static int fmt_autodetect(char * fname, unsigned section); -static FILE *fopen_and_seek(const char *filename, const char *mode, unsigned section) +FILE *fopen_utf8(const char *filename, const char *mode) { - 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; } + if (MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; } - file = _wfopen(fname_buffer, mode_buffer); + return _wfopen(fname_buffer, mode_buffer); #else - file = fopen(filename, mode); + return fopen(filename, mode); #endif +} + +static FILE *fopen_and_seek(const char *filename, const char *mode, unsigned section) +{ + FILE *file = fopen_utf8(filename, mode); if (file == NULL) { return NULL; diff --git a/src/avrdude/jtagmkII.c b/src/avrdude/jtagmkII.c index 78c412ce6..d14c4ce74 100644 --- a/src/avrdude/jtagmkII.c +++ b/src/avrdude/jtagmkII.c @@ -1527,8 +1527,10 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port) */ jtagmkII_drain(pgm, 0); - if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) + if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } @@ -1579,8 +1581,10 @@ static int jtagmkII_open_dw(PROGRAMMER * pgm, char * port) */ jtagmkII_drain(pgm, 0); - if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) + if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } @@ -1631,8 +1635,10 @@ static int jtagmkII_open_pdi(PROGRAMMER * pgm, char * port) */ jtagmkII_drain(pgm, 0); - if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) + if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } @@ -1684,8 +1690,10 @@ static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port) */ jtagmkII_drain(pgm, 0); - if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) + if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } @@ -1737,8 +1745,10 @@ static int jtagmkII_dragon_open_dw(PROGRAMMER * pgm, char * port) */ jtagmkII_drain(pgm, 0); - if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) + if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } @@ -1790,8 +1800,10 @@ static int jtagmkII_dragon_open_pdi(PROGRAMMER * pgm, char * port) */ jtagmkII_drain(pgm, 0); - if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) + if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } @@ -3370,6 +3382,8 @@ static int jtagmkII_open32(PROGRAMMER * pgm, char * port) status = jtagmkII_getsync(pgm, -1); if(status < 0) return -1; + // FIXME: Error handling is bad here: memory leak in resp (?) and port not closed + // AVR32 "special" buf[0] = CMND_SET_PARAMETER; buf[1] = 0x2D; diff --git a/src/avrdude/libavrdude.h b/src/avrdude/libavrdude.h index aef792476..5244b362e 100644 --- a/src/avrdude/libavrdude.h +++ b/src/avrdude/libavrdude.h @@ -820,6 +820,8 @@ extern "C" { char * fmtstr(FILEFMT format); +FILE *fopen_utf8(const char *filename, const char *mode); + int fileio(int op, char * filename, FILEFMT format, struct avrpart * p, char * memtype, int size, unsigned section); @@ -939,6 +941,7 @@ int init_config(void); void cleanup_config(void); int read_config(const char * file); +int read_config_builtin(); #ifdef __cplusplus } diff --git a/src/avrdude/main-standalone.c b/src/avrdude/main-standalone.c deleted file mode 100644 index 359a055ca..000000000 --- a/src/avrdude/main-standalone.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "avrdude.h" - - -static const char* SYS_CONFIG = "/etc/avrdude-slic3r.conf"; - -int main(int argc, char *argv[]) -{ - return avrdude_main(argc, argv, SYS_CONFIG); -} diff --git a/src/avrdude/main-standalone.cpp b/src/avrdude/main-standalone.cpp new file mode 100644 index 000000000..df6d79e13 --- /dev/null +++ b/src/avrdude/main-standalone.cpp @@ -0,0 +1,54 @@ +extern "C" { +#include "avrdude.h" +} + + +#ifdef WIN32 +#include +#include + +extern "C" { +#include "windows/utf8.h" +} + +struct ArgvUtf8 : std::vector +{ + int argc; + + ArgvUtf8(int argc_w, wchar_t *argv_w[]) : std::vector(argc_w + 1, nullptr), argc(0) + { + for (int i = 0; i < argc_w; i++) { + char *arg_utf8 = ::wstr_to_utf8(argv_w[i], -1); + if (arg_utf8 != nullptr) { + operator[](i) = arg_utf8; + argc = i + 1; + } else { + break; + } + } + } + + ~ArgvUtf8() + { + for (char *arg : *this) { + if (arg != nullptr) { + ::free(arg); + } + } + } +}; + +int wmain(int argc_w, wchar_t *argv_w[]) +{ + ArgvUtf8 argv_utf8(argc_w, argv_w); + return ::avrdude_main(argv_utf8.argc, &argv_utf8[0]); +} + +#else + +int main(int argc, char *argv[]) +{ + return ::avrdude_main(argc, argv); +} + +#endif diff --git a/src/avrdude/main.c b/src/avrdude/main.c index 2518b7e12..bf56d115c 100644 --- a/src/avrdude/main.c +++ b/src/avrdude/main.c @@ -426,7 +426,7 @@ static int cleanup_main(int status) /* * main routine */ -int avrdude_main(int argc, char * argv [], const char *sys_config) +int avrdude_main(int argc, char * argv []) { int rc; /* general return code checking */ int exitrc; /* exit code for main() */ @@ -807,13 +807,15 @@ int avrdude_main(int argc, char * argv [], const char *sys_config) "%sCopyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/\n" "%sCopyright (c) 2007-2014 Joerg Wunsch\n\n", progname, version, __DATE__, __TIME__, progbuf, progbuf); - avrdude_message(MSG_NOTICE, "%sSystem wide configuration file is \"%s\"\n", - progbuf, sys_config); + // avrdude_message(MSG_NOTICE, "%sSystem wide configuration file is \"%s\"\n", + // progbuf, sys_config); - rc = read_config(sys_config); + // rc = read_config(sys_config); + rc = read_config_builtin(); if (rc) { - avrdude_message(MSG_INFO, "%s: error reading system wide configuration file \"%s\"\n", - progname, sys_config); + // avrdude_message(MSG_INFO, "%s: error reading system wide configuration file \"%s\"\n", + // progname, sys_config); + avrdude_message(MSG_INFO, "%s: error reading built-in configuration file\n", progname); return cleanup_main(1); } @@ -1082,6 +1084,7 @@ int avrdude_main(int argc, char * argv [], const char *sys_config) if (rc < 0) { exitrc = 1; pgm->ppidata = 0; /* clear all bits at exit */ + avrdude_message(MSG_INFO, "%s: Could not open port: %s\n", progname, port); goto main_exit; } is_open = 1; diff --git a/src/avrdude/ser_posix.c b/src/avrdude/ser_posix.c index cb0fc0385..e2afd1c09 100644 --- a/src/avrdude/ser_posix.c +++ b/src/avrdude/ser_posix.c @@ -44,7 +44,7 @@ #include "avrdude.h" #include "libavrdude.h" -long serial_recv_timeout = 5000; /* ms */ +long serial_recv_timeout = 4000; /* ms */ #define MAX_ZERO_READS 512 struct baud_mapping { @@ -150,6 +150,68 @@ static int ser_setspeed(union filedescriptor *fd, long baud) return 0; } + +// Timeout read & write variants +// Additionally to the regular -1 on I/O error, they return -2 on timeout +ssize_t read_timeout(int fd, void *buf, size_t count, long timeout) +{ + struct timeval tm, tm2; + fd_set rfds; + int nfds; + + tm.tv_sec = timeout / 1000L; + tm.tv_usec = (timeout % 1000L) * 1000; + + while (1) { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tm2 = tm; + nfds = select(fd + 1, &rfds, NULL, NULL, &tm2); + + if (nfds == 0) { + return -2; + } else if (nfds == -1) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } else { + return -1; + } + } else { + return read(fd, buf, count); + } + } +} + +ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout) +{ + struct timeval tm, tm2; + fd_set wfds; + int nfds; + + tm.tv_sec = timeout / 1000L; + tm.tv_usec = (timeout % 1000L) * 1000; + + while (1) { + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + tm2 = tm; + nfds = select(fd + 1, NULL, &wfds, NULL, &tm2); + + if (nfds == 0) { + return -2; + } else if (nfds == -1) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } else { + return -1; + } + } else { + return write(fd, buf, count); + } + } +} + + /* * Given a port description of the form :, open a TCP * connection to the specified destination, which is assumed to be a @@ -314,6 +376,7 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t int rc; const unsigned char * p = buf; size_t len = buflen; + unsigned zero_writes = 0; if (!len) return 0; @@ -341,14 +404,25 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t while (len) { RETURN_IF_CANCEL(); - rc = write(fd->ifd, p, (len > 1024) ? 1024 : len); - if (rc < 0) { - avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", - progname, strerror(errno)); + rc = write_timeout(fd->ifd, p, (len > 1024) ? 1024 : len, serial_recv_timeout); + if (rc == -2) { + avrdude_message(MSG_NOTICE2, "%s: ser_send(): programmer is not responding\n", progname); return -1; + } else if (rc == -1) { + avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, strerror(errno)); + return -1; + } else if (rc == 0) { + zero_writes++; + if (zero_writes > MAX_ZERO_READS) { + avrdude_message(MSG_NOTICE2, "%s: ser_send(): programmer is not responding (too many zero writes)\n", + progname); + return -1; + } + } else { + zero_writes = 0; + p += rc; + len -= rc; } - p += rc; - len -= rc; } return 0; @@ -357,51 +431,21 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) { - struct timeval timeout, to2; - fd_set rfds; - int nfds; int rc; unsigned char * p = buf; size_t len = 0; unsigned zero_reads = 0; - timeout.tv_sec = serial_recv_timeout / 1000L; - timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000; - to2 = timeout; - while (len < buflen) { - reselect: RETURN_IF_CANCEL(); - FD_ZERO(&rfds); - FD_SET(fd->ifd, &rfds); - 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) { - avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", - progname); + rc = read_timeout(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, serial_recv_timeout); + + if (rc == -2) { + avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname); return -1; - } - else if (nfds == -1) { - if (errno == EINTR || errno == EAGAIN) { - avrdude_message(MSG_INFO, "%s: ser_recv(): programmer is not responding,reselecting\n", - progname); - goto reselect; - } - else { - avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", - progname, strerror(errno)); - return -1; - } - } - - rc = read(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len); - if (rc < 0) { - avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", - progname, strerror(errno)); + } else if (rc == -1) { + avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, strerror(errno)); return -1; } else if (rc == 0) { zero_reads++; @@ -445,49 +489,26 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen static int ser_drain(union filedescriptor *fd, int display) { - struct timeval timeout; - fd_set rfds; - int nfds; int rc; unsigned char buf; unsigned zero_reads = 0; - timeout.tv_sec = 0; - timeout.tv_usec = 250000; - if (display) { avrdude_message(MSG_INFO, "drain>"); } while (1) { - FD_ZERO(&rfds); - FD_SET(fd->ifd, &rfds); - - reselect: RETURN_IF_CANCEL(); - nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout); - if (nfds == 0) { + + rc = read_timeout(fd->ifd, &buf, 1, 250); // Note: timeout needs to be kept low to not timeout in programmers + if (rc == -2) { if (display) { avrdude_message(MSG_INFO, "ifd, &buf, 1); - if (rc < 0) { - avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", - progname, strerror(errno)); + break; + } else if (rc == -1) { + avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, strerror(errno)); return -1; } else if (rc == 0) { zero_reads++; diff --git a/src/avrdude/ser_win32.c b/src/avrdude/ser_win32.c index 4e1713128..8efca0397 100644 --- a/src/avrdude/ser_win32.c +++ b/src/avrdude/ser_win32.c @@ -34,16 +34,63 @@ #include #include +#include #include /* for isprint */ #include /* ENOTTY */ #include "avrdude.h" #include "libavrdude.h" +#include "windows/utf8.h" long serial_recv_timeout = 5000; /* ms */ #define W32SERBUFSIZE 1024 + +// Get last error message string in UTF-8 +// Always return a valid null-terminated string +// The returned string should be freed by the caller +char* last_error_string(int wsa) +{ + LPWSTR wbuffer = NULL; + + (void)wsa; + + DWORD wbuffer_len = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, +#ifdef HAVE_LIBWS2_32 + wsa ? WSAGetLastError() : GetLastError(), +#else + GetLastError(), +#endif + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&wbuffer, + 0, + NULL); + + if (wbuffer_len == 0) { + return NULL; + } + + char *res = wstr_to_utf8(wbuffer, wbuffer_len); + + LocalFree(wbuffer); + + if (res == NULL) { + // If we get here, conversion to UTF-8 failed + res = strdup("(could not get error message)"); + if (res == NULL) { + avrdude_oom("last_error_string(): out of memory\n"); + } + } + + return res; +} + + struct baud_mapping { long baud; DWORD speed; @@ -95,6 +142,7 @@ static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms // ctmo.ReadIntervalTimeout = timeout; // ctmo.ReadTotalTimeoutMultiplier = timeout; ctmo.ReadTotalTimeoutConstant = timeout; + ctmo.WriteTotalTimeoutConstant = timeout; return SetCommTimeouts(hComPort, &ctmo); } @@ -129,7 +177,6 @@ static int net_open(const char *port, union filedescriptor *fdp) { WSADATA wsaData; - LPVOID lpMsgBuf; char *hstr, *pstr, *end; unsigned int pnum; @@ -175,18 +222,10 @@ net_open(const char *port, union filedescriptor *fdp) free(hstr); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, error); + free(error); + return -1; } @@ -196,18 +235,9 @@ net_open(const char *port, union filedescriptor *fdp) memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname); + free(error); return -1; } @@ -221,7 +251,6 @@ net_open(const char *port, union filedescriptor *fdp) static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) { - LPVOID lpMsgBuf; HANDLE hComPort=INVALID_HANDLE_VALUE; char *newname = 0; @@ -261,19 +290,9 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hComPort == INVALID_HANDLE_VALUE) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", - progname, port, (char*)lpMsgBuf); - LocalFree( lpMsgBuf ); + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error); + free(error); return -1; } @@ -346,14 +365,13 @@ static int ser_set_dtr_rts(union filedescriptor *fd, int is_on) #ifdef HAVE_LIBWS2_32 static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen) { - LPVOID lpMsgBuf; int rc; const unsigned char *p = buf; size_t len = buflen; if (fd->ifd < 0) { avrdude_message(MSG_NOTICE, "%s: net_send(): connection not open\n", progname); - exit(1); + return -1; } if (!len) { @@ -382,19 +400,10 @@ static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t while (len) { rc = send(fd->ifd, p, (len > 1024) ? 1024 : len, 0); if (rc < 0) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); - exit(1); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, error); + free(error); + return -1; } p += rc; len -= rc; @@ -423,8 +432,7 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t HANDLE hComPort=(HANDLE)fd->pfd; if (hComPort == INVALID_HANDLE_VALUE) { - avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n", - progname); + avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n", progname); return -1; } @@ -449,18 +457,18 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t } avrdude_message(MSG_INFO, "\n"); } - + serial_w32SetTimeOut(hComPort,500); - if (!WriteFile (hComPort, buf, buflen, &written, NULL)) { - avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", - progname, "sorry no info avail"); // TODO + if (!WriteFile(hComPort, buf, buflen, &written, NULL)) { + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error); + free(error); return -1; } if (written != buflen) { - avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n", - progname); + avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n", progname); return -1; } @@ -471,7 +479,6 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t #ifdef HAVE_LIBWS2_32 static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) { - LPVOID lpMsgBuf; struct timeval timeout, to2; fd_set rfds; int nfds; @@ -481,7 +488,7 @@ static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen if (fd->ifd < 0) { avrdude_message(MSG_INFO, "%s: net_recv(): connection not open\n", progname); - exit(1); + return -1; } timeout.tv_sec = serial_recv_timeout / 1000L; @@ -504,37 +511,19 @@ reselect: avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding, reselecting\n", progname); goto reselect; } else { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); - exit(1); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, error); + free(error); + return -1; } } rc = recv(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, 0); if (rc < 0) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); - exit(1); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); + free(error); + return -1; } p += rc; len += rc; @@ -579,37 +568,24 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen RETURN_IF_CANCEL(); HANDLE hComPort=(HANDLE)fd->pfd; - + if (hComPort == INVALID_HANDLE_VALUE) { - avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n", - progname); + avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n", progname); return -1; } - + serial_w32SetTimeOut(hComPort, serial_recv_timeout); - + if (!ReadFile(hComPort, buf, buflen, &read, NULL)) { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL ); - avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", - progname, (char*)lpMsgBuf); - LocalFree( lpMsgBuf ); + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); + free(error); return -1; } /* time out detected */ if (read == 0) { - avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", - progname); + avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname); return -1; } @@ -664,20 +640,9 @@ static int ser_drain(union filedescriptor *fd, int display) readres=ReadFile(hComPort, buf, 1, &read, NULL); if (!readres) { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL ); - avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", - progname, (char*)lpMsgBuf); - LocalFree( lpMsgBuf ); + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error); + free(error); return -1; } diff --git a/src/avrdude/stk500.c b/src/avrdude/stk500.c index 63deb228f..efb7078bc 100644 --- a/src/avrdude/stk500.c +++ b/src/avrdude/stk500.c @@ -669,11 +669,15 @@ static int stk500_open(PROGRAMMER * pgm, char * port) // MIB510 init if (strcmp(ldata(lfirst(pgm->id)), "mib510") == 0 && - mib510_isp(pgm, 1) != 0) + mib510_isp(pgm, 1) != 0) { + serial_close(&pgm->fd); return -1; + } - if (stk500_getsync(pgm) < 0) + if (stk500_getsync(pgm) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } diff --git a/src/avrdude/stk500v2.c b/src/avrdude/stk500v2.c index 691152b46..9bc629ba4 100644 --- a/src/avrdude/stk500v2.c +++ b/src/avrdude/stk500v2.c @@ -1695,8 +1695,10 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port) stk500v2_drain(pgm, 0); if (pgm->bitclock != 0.0) { - if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) + if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) { + serial_close(&pgm->fd); return -1; + } } return 0; @@ -1753,8 +1755,10 @@ static int stk600_open(PROGRAMMER * pgm, char * port) stk500v2_drain(pgm, 0); if (pgm->bitclock != 0.0) { - if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) + if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) { + serial_close(&pgm->fd); return -1; + } } return 0; diff --git a/src/avrdude/windows/utf8.c b/src/avrdude/windows/utf8.c new file mode 100644 index 000000000..d3c51e67f --- /dev/null +++ b/src/avrdude/windows/utf8.c @@ -0,0 +1,45 @@ +#include "utf8.h" + + +char* wstr_to_utf8(LPWSTR wstr, int len) +{ + char *res = NULL; + + int res_size = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL); + if (res_size > 0) { + // Note: WideCharToMultiByte doesn't null-terminate if real (ie. > 0) buffer length is passed + res = malloc(len != - 1 ? res_size + 1 : res_size); + if (res == NULL) { return NULL; } + + if (WideCharToMultiByte(CP_UTF8, 0, wstr, len, res, res_size, NULL, NULL) == res_size) { + if (len != -1) { res[res_size] = '\0'; } + } else { + free(res); + return NULL; + } + } + + return res; +} + +LPWSTR utf8_to_wstr(const char *str, int len) +{ + LPWSTR res = NULL; + + int res_size = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + if (res_size > 0) { + // Note: MultiByteToWideChar doesn't null-terminate if real (ie. > 0) buffer length is passed + res = malloc(len != - 1 ? res_size + 1 : res_size); + + if (res == NULL) { return NULL; } + + if (MultiByteToWideChar(CP_UTF8, 0, str, len, res, res_size) == res_size) { + if (len != -1) { res[res_size] = L'\0'; } + } else { + free(res); + return NULL; + } + } + + return res; +} diff --git a/src/avrdude/windows/utf8.h b/src/avrdude/windows/utf8.h new file mode 100644 index 000000000..a99fcbb7e --- /dev/null +++ b/src/avrdude/windows/utf8.h @@ -0,0 +1,10 @@ +#ifndef SLIC3R_AVRDUDE_UTF8_H +#define SLIC3R_AVRDUDE_UTF8_H + +#include + +extern char* wstr_to_utf8(LPWSTR wstr, int len); +extern LPWSTR utf8_to_wstr(const char *str, int len); + + +#endif // SLIC3R_AVRDUDE_UTF8_H diff --git a/src/avrdude/wiring.c b/src/avrdude/wiring.c index 562a3f17c..85a8532d2 100644 --- a/src/avrdude/wiring.c +++ b/src/avrdude/wiring.c @@ -192,8 +192,10 @@ static int wiring_open(PROGRAMMER * pgm, char * port) /* drain any extraneous input */ stk500v2_drain(pgm, 0); - if (stk500v2_getsync(pgm) < 0) + if (stk500v2_getsync(pgm) < 0) { + serial_close(&pgm->fd); return -1; + } return 0; } diff --git a/src/libnest2d/include/libnest2d/optimizer.hpp b/src/libnest2d/include/libnest2d/optimizer.hpp index 78e105598..962a47392 100644 --- a/src/libnest2d/include/libnest2d/optimizer.hpp +++ b/src/libnest2d/include/libnest2d/optimizer.hpp @@ -163,7 +163,7 @@ public: { dir_ = OptDir::MIN; return static_cast(this)->template optimize( - objectfunction, initvals, Bound()... ); + forward(objectfunction), initvals, Bound()... ); } template @@ -171,7 +171,7 @@ public: { dir_ = OptDir::MIN; return static_cast(this)->template optimize( - objectfunction, + forward(objectfunction), Input(), Bound()... ); } @@ -184,7 +184,7 @@ public: { dir_ = OptDir::MAX; return static_cast(this)->template optimize( - objectfunction, initvals, bounds... ); + forward(objectfunction), initvals, bounds... ); } template @@ -193,7 +193,7 @@ public: { dir_ = OptDir::MAX; return static_cast(this)->template optimize( - objectfunction, initvals, Bound()... ); + forward(objectfunction), initvals, Bound()... ); } template @@ -201,7 +201,7 @@ public: { dir_ = OptDir::MAX; return static_cast(this)->template optimize( - objectfunction, + forward(objectfunction), Input(), Bound()... ); } diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index d3548208f..9a851bbf9 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -103,8 +103,9 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) if (surface.has_fill_solid() && (!surface.has_mod_bridge() || layerm.layer()->id() == 0) && !surface.has_mod_overBridge()) { group_attrib[i].is_solid = true; group_attrib[i].flow_width = (surface.has_pos_top()) ? top_solid_infill_flow.width : solid_infill_flow.width; - group_attrib[i].pattern = surface.has_pos_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().solid_fill_pattern.value; - group_attrib[i].pattern = surface.has_pos_bottom() ? layerm.region()->config().bottom_fill_pattern.value : layerm.region()->config().solid_fill_pattern.value; + group_attrib[i].pattern = surface.has_pos_external() ? + (surface.has_pos_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) : + layerm.region()->config().solid_fill_pattern.value; } } // Loop through solid groups, find compatible groups and append them to this one. diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 8b0c28cd6..d2b9b08f3 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -6,6 +6,8 @@ #include "3mf.hpp" +#include + #include #include #include @@ -323,7 +325,7 @@ namespace Slic3r { typedef std::map IdToMetadataMap; typedef std::map IdToGeometryMap; typedef std::map> IdToLayerHeightsProfileMap; - typedef std::map> IdToSlaSupportPointsMap; + typedef std::map> IdToSlaSupportPointsMap; // Version of the 3mf file unsigned int m_version; @@ -776,10 +778,19 @@ namespace Slic3r { std::vector objects; boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off); + // Info on format versioning - see 3mf.hpp + int version = 0; + if (!objects.empty() && objects[0].find("support_points_format_version=") != std::string::npos) { + objects[0].erase(objects[0].begin(), objects[0].begin() + 30); // removes the string + version = std::stoi(objects[0]); + objects.erase(objects.begin()); // pop the header + } + for (const std::string& object : objects) { std::vector object_data; boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off); + if (object_data.size() != 2) { add_error("Error while reading object data"); @@ -811,10 +822,24 @@ namespace Slic3r { std::vector object_data_points; boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off); - std::vector sla_support_points; + std::vector sla_support_points; - for (unsigned int i=0; i()); + if (version == 0) { + for (unsigned int i=0; iname = metadata.value; else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1")) - volume->set_type(ModelVolume::PARAMETER_MODIFIER); + volume->set_type(ModelVolumeType::PARAMETER_MODIFIER); else if (metadata.key == VOLUME_TYPE_KEY) volume->set_type(ModelVolume::type_from_string(metadata.value)); else @@ -1726,6 +1751,11 @@ namespace Slic3r { bool _3MF_Exporter::_add_model_file_to_archive(mz_zip_archive& archive, Model& model) { std::stringstream stream; + // https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10 + // Conversion of a floating-point value to text and back is exact as long as at least max_digits10 were used (9 for float, 17 for double). + // It is guaranteed to produce the same floating-point value, even though the intermediate text representation is not exact. + // The default value of std::stream precision is 6 digits only! + stream << std::setprecision(std::numeric_limits::max_digits10); stream << "\n"; stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:slic3rpe=\"http://schemas.slic3r.org/3mf/2017/06\">\n"; stream << " <" << METADATA_TAG << " name=\"" << SLIC3RPE_3MF_VERSION << "\">" << VERSION_3MF << "\n"; @@ -1841,7 +1871,7 @@ namespace Slic3r { for (int i = 0; i < stl.stats.shared_vertices; ++i) { stream << " <" << VERTEX_TAG << " "; - Vec3d v = matrix * stl.v_shared[i].cast(); + Vec3f v = (matrix * stl.v_shared[i].cast()).cast(); stream << "x=\"" << v(0) << "\" "; stream << "y=\"" << v(1) << "\" "; stream << "z=\"" << v(2) << "\" />\n"; @@ -1961,7 +1991,7 @@ namespace Slic3r { for (const ModelObject* object : model.objects) { ++count; - const std::vector& sla_support_points = object->sla_support_points; + const std::vector& sla_support_points = object->sla_support_points; if (!sla_support_points.empty()) { sprintf(buffer, "object_id=%d|", count); @@ -1970,7 +2000,7 @@ namespace Slic3r { // Store the layer height profile as a single space separated list. for (size_t i = 0; i < sla_support_points.size(); ++i) { - sprintf(buffer, (i==0 ? "%f %f %f" : " %f %f %f"), sla_support_points[i](0), sla_support_points[i](1), sla_support_points[i](2)); + sprintf(buffer, (i==0 ? "%f %f %f %f %f" : " %f %f %f %f %f"), sla_support_points[i].pos(0), sla_support_points[i].pos(1), sla_support_points[i].pos(2), sla_support_points[i].head_front_radius, (float)sla_support_points[i].is_new_island); out += buffer; } out += "\n"; @@ -1979,6 +2009,9 @@ namespace Slic3r { if (!out.empty()) { + // Adds version header at the beginning: + out = std::string("support_points_format_version=") + std::to_string(support_points_format_version) + std::string("\n") + out; + if (!mz_zip_writer_add_mem(&archive, SLA_SUPPORT_POINTS_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { add_error("Unable to add sla support points file to archive"); diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index 44b37c1ae..b5927651e 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -3,6 +3,23 @@ namespace Slic3r { + /* The format for saving the SLA points was changing in the past. This enum holds the latest version that is being currently used. + * Examples of the Slic3r_PE_sla_support_points.txt for historically used versions: + + * version 0 : object_id=1|-12.055421 -2.658771 10.000000 + object_id=2|-14.051745 -3.570338 5.000000 + // no header and x,y,z positions of the points) + + * version 1 : ThreeMF_support_points_version=1 + object_id=1|-12.055421 -2.658771 10.000000 0.4 0.0 + object_id=2|-14.051745 -3.570338 5.000000 0.6 1.0 + // introduced header with version number; x,y,z,head_size,is_new_island) + */ + + enum { + support_points_format_version = 1 + }; + class Model; class DynamicPrintConfig; diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 9791b1502..35c90a00c 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -583,7 +584,7 @@ void AMFParserContext::endElement(const char * /* name */) else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) { // Parse object's layer height profile, a semicolon separated list of floats. unsigned char coord_idx = 0; - Vec3f point(Vec3f::Zero()); + Eigen::Matrix point(Eigen::Matrix::Zero()); char *p = const_cast(m_value[1].c_str()); for (;;) { char *end = strchr(p, ';'); @@ -591,8 +592,8 @@ void AMFParserContext::endElement(const char * /* name */) *end = 0; point(coord_idx) = atof(p); - if (++coord_idx == 3) { - m_object->sla_support_points.push_back(point); + if (++coord_idx == 5) { + m_object->sla_support_points.push_back(sla::SupportPoint(point)); coord_idx = 0; } if (end == nullptr) @@ -604,7 +605,7 @@ void AMFParserContext::endElement(const char * /* name */) if (strcmp(opt_key, "modifier") == 0) { // Is this volume a modifier volume? // "modifier" flag comes first in the XML file, so it may be later overwritten by the "type" flag. - m_volume->set_type((atoi(m_value[1].c_str()) == 1) ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART); + m_volume->set_type((atoi(m_value[1].c_str()) == 1) ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART); } else if (strcmp(opt_key, "volume_type") == 0) { m_volume->set_type(ModelVolume::type_from_string(m_value[1])); } @@ -856,6 +857,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) return false; std::stringstream stream; + // https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10 + // Conversion of a floating-point value to text and back is exact as long as at least max_digits10 were used (9 for float, 17 for double). + // It is guaranteed to produce the same floating-point value, even though the intermediate text representation is not exact. + // The default value of std::stream precision is 6 digits only! + stream << std::setprecision(std::numeric_limits::max_digits10); stream << "\n"; stream << "\n"; stream << "Slic3r " << SLIC3R_VERSION << "\n"; @@ -900,14 +906,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) } //FIXME Store the layer height ranges (ModelObject::layer_height_ranges) - const std::vector& sla_support_points = object->sla_support_points; + const std::vector& sla_support_points = object->sla_support_points; if (!sla_support_points.empty()) { // Store the SLA supports as a single semicolon separated list. stream << " "; for (size_t i = 0; i < sla_support_points.size(); ++i) { if (i != 0) stream << ";"; - stream << sla_support_points[i](0) << ";" << sla_support_points[i](1) << ";" << sla_support_points[i](2); + stream << sla_support_points[i].pos(0) << ";" << sla_support_points[i].pos(1) << ";" << sla_support_points[i].pos(2) << ";" << sla_support_points[i].head_front_radius << ";" << sla_support_points[i].is_new_island; } stream << "\n \n"; } @@ -927,7 +933,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) for (size_t i = 0; i < stl.stats.shared_vertices; ++i) { stream << " \n"; stream << " \n"; - Vec3d v = matrix * stl.v_shared[i].cast(); + Vec3f v = (matrix * stl.v_shared[i].cast()).cast(); stream << " " << v(0) << "\n"; stream << " " << v(1) << "\n"; stream << " " << v(2) << "\n"; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3992775c0..4e469bfb0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2636,8 +2636,14 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string m_last_extrusion_role = path.role(); // adds analyzer tags and updates analyzer's tracking data - if (m_enable_analyzer) { - if (path.role() != m_last_analyzer_extrusion_role) { + if (m_enable_analyzer) + { + // PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width + // so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines + bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower); + + if (path.role() != m_last_analyzer_extrusion_role) + { m_last_analyzer_extrusion_role = path.role(); char buf[32]; sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), int(m_last_analyzer_extrusion_role)); @@ -2652,7 +2658,8 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string gcode += buf; } - if (m_last_width != path.width) { + if (last_was_wipe_tower || (m_last_width != path.width)) + { m_last_width = path.width; char buf[32]; @@ -2660,7 +2667,8 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string gcode += buf; } - if (m_last_height != path.height) { + if (last_was_wipe_tower || (m_last_height != path.height)) + { m_last_height = path.height; char buf[32]; diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 06fbf2fed..4f833f5f3 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -482,6 +482,7 @@ public: bool arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions) { + std::cout << "calling geometry::arrange()\n"; positions.clear(); Vec2d part = part_size; diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 5326b94da..87d19d4a5 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -212,6 +212,7 @@ public: void set_scaling_factor(const Vec3d& scaling_factor); void set_scaling_factor(Axis axis, double scaling_factor); + bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } const Vec3d& get_mirror() const { return m_mirror; } double get_mirror(Axis axis) const { return m_mirror(axis); } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 422717279..9c5f8c826 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -592,6 +592,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->input_file = rhs.input_file; this->config = rhs.config; this->sla_support_points = rhs.sla_support_points; + this->sla_points_status = rhs.sla_points_status; this->layer_height_ranges = rhs.layer_height_ranges; this->layer_height_profile = rhs.layer_height_profile; this->origin_translation = rhs.origin_translation; @@ -625,6 +626,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->input_file = std::move(rhs.input_file); this->config = std::move(rhs.config); this->sla_support_points = std::move(rhs.sla_support_points); + this->sla_points_status = std::move(rhs.sla_points_status); this->layer_height_ranges = std::move(rhs.layer_height_ranges); this->layer_height_profile = std::move(rhs.layer_height_profile); this->origin_translation = std::move(rhs.origin_translation); @@ -1130,6 +1132,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_upper) { upper->set_model(nullptr); upper->sla_support_points.clear(); + upper->sla_points_status = sla::PointsStatus::None; upper->clear_volumes(); upper->input_file = ""; } @@ -1137,6 +1140,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_lower) { lower->set_model(nullptr); lower->sla_support_points.clear(); + lower->sla_points_status = sla::PointsStatus::None; lower->clear_volumes(); lower->input_file = ""; } @@ -1480,32 +1484,32 @@ const TriangleMesh& ModelVolume::get_convex_hull() const return m_convex_hull; } -ModelVolume::Type ModelVolume::type_from_string(const std::string &s) +ModelVolumeType ModelVolume::type_from_string(const std::string &s) { // Legacy support if (s == "1") - return PARAMETER_MODIFIER; + return ModelVolumeType::PARAMETER_MODIFIER; // New type (supporting the support enforcers & blockers) if (s == "ModelPart") - return MODEL_PART; + return ModelVolumeType::MODEL_PART; if (s == "ParameterModifier") - return PARAMETER_MODIFIER; + return ModelVolumeType::PARAMETER_MODIFIER; if (s == "SupportEnforcer") - return SUPPORT_ENFORCER; + return ModelVolumeType::SUPPORT_ENFORCER; if (s == "SupportBlocker") - return SUPPORT_BLOCKER; + return ModelVolumeType::SUPPORT_BLOCKER; assert(s == "0"); // Default value if invalud type string received. - return MODEL_PART; + return ModelVolumeType::MODEL_PART; } -std::string ModelVolume::type_to_string(const Type t) +std::string ModelVolume::type_to_string(const ModelVolumeType t) { switch (t) { - case MODEL_PART: return "ModelPart"; - case PARAMETER_MODIFIER: return "ParameterModifier"; - case SUPPORT_ENFORCER: return "SupportEnforcer"; - case SUPPORT_BLOCKER: return "SupportBlocker"; + case ModelVolumeType::MODEL_PART: return "ModelPart"; + case ModelVolumeType::PARAMETER_MODIFIER: return "ParameterModifier"; + case ModelVolumeType::SUPPORT_ENFORCER: return "SupportEnforcer"; + case ModelVolumeType::SUPPORT_BLOCKER: return "SupportBlocker"; default: assert(false); return "ModelPart"; @@ -1671,7 +1675,7 @@ bool model_object_list_extended(const Model &model_old, const Model &model_new) return true; } -bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type) +bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type) { bool modifiers_differ = false; size_t i_old, i_new; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b998fbb7d..a4b32d93f 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -12,6 +12,7 @@ #include #include #include "Geometry.hpp" +#include namespace Slic3r { @@ -48,6 +49,8 @@ struct ModelID bool operator<=(const ModelID &rhs) const { return this->id <= rhs.id; } bool operator>=(const ModelID &rhs) const { return this->id >= rhs.id; } + bool valid() const { return id != 0; } + size_t id; }; @@ -175,7 +178,11 @@ public: // This vector holds position of selected support points for SLA. The data are // saved in mesh coordinates to allow using them for several instances. - std::vector sla_support_points; + // The format is (x, y, z, point_size, supports_island) + std::vector sla_support_points; + // To keep track of where the points came from (used for synchronization between + // the SLA gizmo and the backend). + sla::PointsStatus sla_points_status = sla::PointsStatus::None; /* This vector accumulates the total translation applied to the object by the center_around_origin() method. Callers might want to apply the same translation @@ -291,6 +298,15 @@ private: mutable bool m_raw_mesh_bounding_box_valid; }; +// Declared outside of ModelVolume, so it could be forward declared. +enum class ModelVolumeType : int { + INVALID = -1, + MODEL_PART = 0, + PARAMETER_MODIFIER, + SUPPORT_ENFORCER, + SUPPORT_BLOCKER, +}; + // An object STL, or a modifier volume, over which a different set of parameters shall be applied. // ModelVolume instances are owned by a ModelObject. class ModelVolume : public ModelBase @@ -303,23 +319,15 @@ public: // overriding the global Slic3r settings and the ModelObject settings. DynamicPrintConfig config; - enum Type { - MODEL_TYPE_INVALID = -1, - MODEL_PART = 0, - PARAMETER_MODIFIER, - SUPPORT_ENFORCER, - SUPPORT_BLOCKER, - }; - // A parent object owning this modifier volume. ModelObject* get_object() const { return this->object; }; - Type type() const { return m_type; } - void set_type(const Type t) { m_type = t; } - bool is_model_part() const { return m_type == MODEL_PART; } - bool is_modifier() const { return m_type == PARAMETER_MODIFIER; } - bool is_support_enforcer() const { return m_type == SUPPORT_ENFORCER; } - bool is_support_blocker() const { return m_type == SUPPORT_BLOCKER; } - bool is_support_modifier() const { return m_type == SUPPORT_BLOCKER || m_type == SUPPORT_ENFORCER; } + ModelVolumeType type() const { return m_type; } + void set_type(const ModelVolumeType t) { m_type = t; } + bool is_model_part() const { return m_type == ModelVolumeType::MODEL_PART; } + bool is_modifier() const { return m_type == ModelVolumeType::PARAMETER_MODIFIER; } + bool is_support_enforcer() const { return m_type == ModelVolumeType::SUPPORT_ENFORCER; } + bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; } + bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; } t_model_material_id material_id() const { return m_material_id; } void set_material_id(t_model_material_id material_id); ModelMaterial* material() const; @@ -353,8 +361,8 @@ public: const TriangleMesh& get_convex_hull() const; // Helpers for loading / storing into AMF / 3MF files. - static Type type_from_string(const std::string &s); - static std::string type_to_string(const Type t); + static ModelVolumeType type_from_string(const std::string &s); + static std::string type_to_string(const ModelVolumeType t); const Geometry::Transformation& get_transformation() const { return m_transformation; } void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; } @@ -399,7 +407,7 @@ private: // Parent object owning this ModelVolume. ModelObject* object; // Is it an object to be printed, or a modifier volume? - Type m_type; + ModelVolumeType m_type; t_model_material_id m_material_id; // The convex hull of this model's mesh. TriangleMesh m_convex_hull; @@ -411,13 +419,13 @@ private: // 1 -> is splittable int m_is_splittable {-1}; - ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object) + ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object) { if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : - mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {} + mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(ModelVolumeType::MODEL_PART), object(object) {} // Copying an existing volume, therefore this volume will get a copy of the ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other) : @@ -629,7 +637,7 @@ extern bool model_object_list_extended(const Model &model_old, const Model &mode // Test whether the new ModelObject contains a different set of volumes (or sorted in a different order) // than the old ModelObject. -extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type); +extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type); #ifndef NDEBUG // Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique. diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 94c2770a6..74972a115 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -22,6 +22,7 @@ typedef Point Vector; // Vector types with a fixed point coordinate base type. typedef Eigen::Matrix Vec2crd; typedef Eigen::Matrix Vec3crd; +typedef Eigen::Matrix Vec2i; typedef Eigen::Matrix Vec3i; typedef Eigen::Matrix Vec2i64; typedef Eigen::Matrix Vec3i64; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3e5d88015..76072d06e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -286,7 +286,7 @@ bool Print::is_step_done(PrintObjectStep step) const return false; tbb::mutex::scoped_lock lock(this->state_mutex()); for (const PrintObject *object : m_objects) - if (! object->m_state.is_done_unguarded(step)) + if (! object->is_step_done_unguarded(step)) return false; return true; } @@ -555,10 +555,14 @@ void Print::model_volume_list_update_supports(ModelObject &model_object_dst, con assert(! it->second); // not consumed yet it->second = true; ModelVolume *model_volume_dst = const_cast(it->first); - assert(model_volume_dst->type() == model_volume_src->type()); + // For support modifiers, the type may have been switched from blocker to enforcer and vice versa. + assert((model_volume_dst->is_support_modifier() && model_volume_src->is_support_modifier()) || model_volume_dst->type() == model_volume_src->type()); model_object_dst.volumes.emplace_back(model_volume_dst); - if (model_volume_dst->is_support_modifier()) - model_volume_dst->set_transformation(model_volume_src->get_transformation()); + if (model_volume_dst->is_support_modifier()) { + // For support modifiers, the type may have been switched from blocker to enforcer and vice versa. + model_volume_dst->set_type(model_volume_src->type()); + model_volume_dst->set_transformation(model_volume_src->get_transformation()); + } assert(model_volume_dst->get_matrix().isApprox(model_volume_src->get_matrix())); } else { // The volume was not found in the old list. Create a new copy. @@ -573,7 +577,7 @@ void Print::model_volume_list_update_supports(ModelObject &model_object_dst, con delete mv_with_status.first; } -static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolume::Type type) +static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolumeType type) { size_t i_src, i_dst; for (i_src = 0, i_dst = 0; i_src < model_object_src.volumes.size() && i_dst < model_object_dst.volumes.size();) { @@ -719,7 +723,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (model.id() != m_model.id()) { // Kill everything, initialize from scratch. // Stop background processing. - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(this->invalidate_all_steps()); for (PrintObject *object : m_objects) { model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); @@ -751,7 +755,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } else { // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(this->invalidate_step(psGCodeExport)); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); @@ -843,10 +847,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved); const ModelObject &model_object_new = *model.objects[idx_model_object]; // Check whether a model part volume was added or removed, their transformations or order changed. - bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::MODEL_PART); - bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::PARAMETER_MODIFIER); - bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_BLOCKER); - bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_ENFORCER); + bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); + bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER); + bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER); + bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER); if (model_parts_differ || modifiers_differ || model_object.origin_translation != model_object_new.origin_translation || model_object.layer_height_ranges != model_object_new.layer_height_ranges || @@ -861,7 +865,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co model_object.assign_copy(model_object_new); } else if (support_blockers_differ || support_enforcers_differ) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(false); // Invalidate just the supports step. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); @@ -888,8 +892,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } // Synchronize (just copy) the remaining data of ModelVolumes (name, config). //FIXME What to do with m_material_id? - model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolume::MODEL_PART); - model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolume::PARAMETER_MODIFIER); + model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART); + model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER); // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; @@ -962,7 +966,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } } if (m_objects != print_objects_new) { - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(this->invalidate_all_steps()); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. @@ -1513,7 +1517,8 @@ void Print::export_gcode(const std::string &path_template, GCodePreviewData *pre // The following call may die if the output_filename_format template substitution fails. std::string path = this->output_filepath(path_template); std::string message = "Exporting G-code"; - if (! path.empty()) { + if (! path.empty() && preview_data == nullptr) { + // Only show the path if preview_data is not set -> running from command line. message += " to "; message += path; } @@ -2035,7 +2040,7 @@ std::string Print::output_filename() const DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); return this->PrintBase::output_filename(m_config.output_filename_format.value, "gcode", &config); } - +/* // Shorten the dhms time by removing the seconds, rounding the dhm to full minutes // and removing spaces. static std::string short_time(const std::string &time) @@ -2075,7 +2080,7 @@ static std::string short_time(const std::string &time) ::sprintf(buffer, "%ds", seconds); return buffer; } - +*/ DynamicConfig PrintStatistics::config() const { DynamicConfig config; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 84d04d26f..e01b678a5 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -62,6 +62,10 @@ public: return state; } + bool is_started(StepType step, tbb::mutex &mtx) const { + return this->state_with_timestamp(step, mtx).state == STARTED; + } + bool is_done(StepType step, tbb::mutex &mtx) const { return this->state_with_timestamp(step, mtx).state == DONE; } @@ -70,6 +74,10 @@ public: return m_state[step]; } + bool is_started_unguarded(StepType step) const { + return this->state_with_timestamp_unguarded(step).state == STARTED; + } + bool is_done_unguarded(StepType step) const { return this->state_with_timestamp_unguarded(step).state == DONE; } @@ -235,7 +243,24 @@ public: virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0; const Model& model() const { return m_model; } + struct TaskParams { + TaskParams() : single_model_object(0), single_model_instance_only(false), to_object_step(-1), to_print_step(-1) {} + // If non-empty, limit the processing to this ModelObject. + ModelID single_model_object; + // If set, only process single_model_object. Otherwise process everything, but single_model_object first. + bool single_model_instance_only; + // If non-negative, stop processing at the successive object step. + int to_object_step; + // If non-negative, stop processing at the successive print step. + int to_print_step; + }; + // After calling the apply() function, call set_task() to limit the task to be processed by process(). + virtual void set_task(const TaskParams ¶ms) {} + // Perform the calculation. This is the only method that is to be called at a worker thread. virtual void process() = 0; + // Clean up after process() finished, either with success, error or if canceled. + // The adjustments on the Print / PrintObject data due to set_task() are to be reverted here. + virtual void finalize() {} struct SlicingStatus { SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {} @@ -244,8 +269,9 @@ public: // Bitmap of flags. enum FlagBits { DEFAULT, - NO_RELOAD_SCENE = 0, - RELOAD_SCENE = 1, + NO_RELOAD_SCENE = 0, + RELOAD_SCENE = 1 << 1, + RELOAD_SLA_SUPPORT_POINTS = 1 << 2, }; // Bitmap of FlagBits unsigned int flags; @@ -300,7 +326,7 @@ protected: tbb::mutex& state_mutex() const { return m_state_mutex; } std::function cancel_callback() { return m_cancel_callback; } - void call_cancell_callback() { m_cancel_callback(); } + void call_cancel_callback() { m_cancel_callback(); } // If the background processing stop was requested, throw CanceledException. // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. @@ -349,6 +375,9 @@ protected: bool invalidate_all_steps() { return m_state.invalidate_all(this->cancel_callback()); } + bool is_step_started_unguarded(PrintStepEnum step) const { return m_state.is_started_unguarded(step); } + bool is_step_done_unguarded(PrintStepEnum step) const { return m_state.is_done_unguarded(step); } + private: PrintState m_state; }; @@ -382,6 +411,9 @@ protected: bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); } + bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); } + bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); } + protected: // If the background processing stop was requested, throw CanceledException. // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 031ed75d3..05118f485 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -59,6 +59,17 @@ void PrintConfigDef::init_common_params() def->cli = "max-print-height=f"; def->mode = comAdvanced; def->default_value = new ConfigOptionFloat(200.0); + + def = this->add("slice_closing_radius", coFloat); + def->label = L("Slice gap closing radius"); + def->category = L("Advanced"); + def->tooltip = L("Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. " + "The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low."); + def->sidetext = L("mm"); + def->cli = "slice-closing-radius=f"; + def->min = 0; + def->mode = comAdvanced; + def->default_value = new ConfigOptionFloat(0.049); } void PrintConfigDef::init_fff_params() @@ -78,15 +89,6 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->default_value = new ConfigOptionBool(false); - def = this->add("remove_small_gaps", coBool); - def->label = L("Remove small gaps"); - def->tooltip = L("Remove the small gaps in the 3D model when slicing. Disable it if you " - "are very confident on your model, or you want to print an item with a geometry " - "designed for vase mode."); - def->cli = "remove-small-gaps!"; - def->mode = comAdvanced; - def->default_value = new ConfigOptionBool(true); - def = this->add("bed_temperature", coInts); def->label = L("Other layers"); def->full_label = L("Bed temperature"); @@ -417,7 +419,7 @@ void PrintConfigDef::init_fff_params() def = this->add("top_fill_pattern", coEnum); def->label = L("Top Pattern"); def->category = L("Infill"); - def->tooltip = L("Fill pattern for top infill. This only affects the top external visible layer, and not its adjacent solid shells."); + def->tooltip = L("Fill pattern for top infill. This only affects the top visible layer, and not its adjacent solid shells."); def->cli = "top-fill-pattern|external-fill-pattern=s"; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("rectilinear"); @@ -443,7 +445,7 @@ void PrintConfigDef::init_fff_params() def = this->add("bottom_fill_pattern", coEnum); def->label = L("Bottom Pattern"); def->category = L("Infill"); - def->tooltip = L("Fill pattern for bottom infill. This only affects the bottom external visible layer, and not its adjacent solid shells."); + def->tooltip = L("Fill pattern for bottom infill. This only affects the bottom visible layer, and not its adjacent solid shells."); def->cli = "bottom-fill-pattern|external-fill-pattern=s"; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("rectilinear"); @@ -2972,6 +2974,32 @@ void PrintConfigDef::init_sla_params() def->enum_labels.push_back(L("Portrait")); def->default_value = new ConfigOptionEnum(sladoPortrait); + def = this->add("fast_tilt_time", coFloat); + def->label = L("Fast"); + def->full_label = L("Fast tilt"); + def->tooltip = L("Time of the fast tilt"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->default_value = new ConfigOptionFloat(5.); + + def = this->add("slow_tilt_time", coFloat); + def->label = L("Slow"); + def->full_label = L("Slow tilt"); + def->tooltip = L("Time of the slow tilt"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->default_value = new ConfigOptionFloat(8.); + + def = this->add("area_fill", coFloat); + def->label = L("Area fill"); + def->tooltip = L("The percentage of the bed area. \nIf the print area exceeds the specified value, \nthen a slow tilt will be used, otherwise - a fast tilt"); + def->sidetext = L("%"); + def->min = 0; + def->mode = comExpert; + def->default_value = new ConfigOptionFloat(50.); + def = this->add("printer_correction", coFloats); def->full_label = L("Printer scaling correction"); def->tooltip = L("Printer scaling correction"); @@ -2987,6 +3015,14 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->default_value = new ConfigOptionFloat(0.3); + def = this->add("faded_layers", coInt); + def->label = L("Faded layers"); + def->tooltip = L("Number of the layers needed for the exposure time fade from initial exposure time to the exposure time"); + def->min = 3; + def->max = 20; + def->mode = comExpert; + def->default_value = new ConfigOptionInt(10); + def = this->add("exposure_time", coFloat); def->label = L("Exposure time"); def->tooltip = L("Exposure time"); @@ -3167,28 +3203,19 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->default_value = new ConfigOptionFloat(5.0); - def = this->add("support_density_at_horizontal", coInt); - def->label = L("Density on horizontal surfaces"); + def = this->add("support_points_density_relative", coInt); + def->label = L("Support points density"); def->category = L("Supports"); - def->tooltip = L("How many support points (approximately) should be placed on horizontal surface."); - def->sidetext = L("points per square dm"); + def->tooltip = L("This is a relative measure of support points density."); + def->sidetext = L("%"); def->cli = ""; def->min = 0; - def->default_value = new ConfigOptionInt(500); + def->default_value = new ConfigOptionInt(100); - def = this->add("support_density_at_45", coInt); - def->label = L("Density on surfaces at 45 degrees"); + def = this->add("support_points_minimal_distance", coFloat); + def->label = L("Minimal distance of the support points"); def->category = L("Supports"); - def->tooltip = L("How many support points (approximately) should be placed on surface sloping at 45 degrees."); - def->sidetext = L("points per square dm"); - def->cli = ""; - def->min = 0; - def->default_value = new ConfigOptionInt(250); - - def = this->add("support_minimal_z", coFloat); - def->label = L("Minimal support point height"); - def->category = L("Supports"); - def->tooltip = L("No support points will be placed lower than this value from the bottom."); + def->tooltip = L("No support points will be placed closer than this threshold."); def->sidetext = L("mm"); def->cli = ""; def->min = 0; @@ -3236,6 +3263,17 @@ void PrintConfigDef::init_sla_params() def->cli = ""; def->min = 0; def->default_value = new ConfigOptionFloat(1.0); + + def = this->add("pad_wall_slope", coFloat); + def->label = L("Pad wall slope"); + def->category = L("Pad"); + def->tooltip = L("The slope of the pad wall relative to the bed plane. " + "90 degrees means straight walls."); + def->sidetext = L("degrees"); + def->cli = ""; + def->min = 45; + def->max = 90; + def->default_value = new ConfigOptionFloat(45.0); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) @@ -3395,13 +3433,38 @@ double PrintConfig::min_object_distance() const double PrintConfig::min_object_distance(const ConfigBase *config) { - double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat(); - double duplicate_distance = config->option("duplicate_distance")->getFloat(); - - // min object distance is max(duplicate_distance, clearance_radius) - return (config->option("complete_objects")->getBool() && extruder_clearance_radius > duplicate_distance) - ? extruder_clearance_radius - : duplicate_distance; + double base_dist = config->option("duplicate_distance")->getFloat(); + if (config->option("complete_objects")->getBool()){ + std::cout << "min distance: complete objects\n"; + std::vector vals = dynamic_cast(config->option("nozzle_diameter"))->values; + double max_nozzle_diam = 0; + for (double val : vals) max_nozzle_diam = std::fmax(max_nozzle_diam, val); + + // min object distance is max(duplicate_distance, clearance_radius) + double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat(); + if (extruder_clearance_radius > base_dist){ + std::cout << "min distance: set for extruder_clearance_radius: " << base_dist << " + " << extruder_clearance_radius << " + " << max_nozzle_diam << "\n"; + base_dist = extruder_clearance_radius + max_nozzle_diam; + } + //add brim width + if (config->option("brim_width")->getFloat() > 0){ + std::cout << "min distance: add for brim_width: " << base_dist << " += " << (config->option("brim_width")->getFloat()) << "\n"; + base_dist += config->option("brim_width")->getFloat(); + } + //add the skirt + if (config->option("skirts")->getInt() > 0){ + //add skirt dist + std::cout << "min distance: set for skirt_distance: " << base_dist << " += " << config->option("skirt_distance")->getFloat() << "\n"; + double dist_skirt = config->option("skirt_distance")->getFloat(); + if (dist_skirt > config->option("brim_width")->getFloat()) + base_dist += dist_skirt - config->option("brim_width")->getFloat(); + //add skirt width + std::cout << "min distance: add for skirts: " << base_dist << " += " << (max_nozzle_diam*config->option("skirts")->getInt()*1.5) << "\n"; + base_dist += max_nozzle_diam * config->option("skirts")->getInt() * 1.5; + } + } + std::cout << "min distance: final=" << base_dist << "\n"; + return base_dist; } std::string FullPrintConfig::validate() diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6da297e11..2f720afc8 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -451,7 +451,6 @@ class PrintObjectConfig : public StaticPrintConfig STATIC_PRINT_CONFIG_CACHE(PrintObjectConfig) public: ConfigOptionBool clip_multipart_objects; - ConfigOptionBool remove_small_gaps; ConfigOptionBool dont_support_bridges; ConfigOptionFloat elefant_foot_compensation; ConfigOptionFloatOrPercent extrusion_width; @@ -466,6 +465,7 @@ public: ConfigOptionBool seam_travel; // ConfigOptionFloat seam_preferred_direction; // ConfigOptionFloat seam_preferred_direction_jitter; + ConfigOptionFloat slice_closing_radius; ConfigOptionBool support_material; // Automatic supports (generated based on support_material_threshold). ConfigOptionBool support_material_auto; @@ -503,7 +503,6 @@ protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { OPT_PTR(clip_multipart_objects); - OPT_PTR(remove_small_gaps); OPT_PTR(dont_support_bridges); OPT_PTR(elefant_foot_compensation); OPT_PTR(extrusion_width); @@ -515,6 +514,7 @@ protected: OPT_PTR(raft_layers); OPT_PTR(seam_position); OPT_PTR(seam_travel); + OPT_PTR(slice_closing_radius); // OPT_PTR(seam_preferred_direction); // OPT_PTR(seam_preferred_direction_jitter); OPT_PTR(support_material); @@ -557,11 +557,11 @@ public: ConfigOptionFloat bridge_flow_ratio; ConfigOptionFloat over_bridge_flow_ratio; ConfigOptionEnum bottom_fill_pattern; + ConfigOptionFloatOrPercent bridged_infill_margin; ConfigOptionFloat bridge_speed; ConfigOptionBool ensure_vertical_shell_thickness; ConfigOptionBool enforce_full_fill_volume; ConfigOptionFloatOrPercent external_infill_margin; - ConfigOptionFloatOrPercent bridged_infill_margin; ConfigOptionFloatOrPercent external_perimeter_extrusion_width; ConfigOptionFloatOrPercent external_perimeter_speed; ConfigOptionBool external_perimeters_first; @@ -616,11 +616,11 @@ protected: OPT_PTR(bridge_flow_ratio); OPT_PTR(over_bridge_flow_ratio); OPT_PTR(bottom_fill_pattern); + OPT_PTR(bridged_infill_margin); OPT_PTR(bridge_speed); OPT_PTR(ensure_vertical_shell_thickness); OPT_PTR(enforce_full_fill_volume); OPT_PTR(external_infill_margin); - OPT_PTR(bridged_infill_margin); OPT_PTR(external_perimeter_extrusion_width); OPT_PTR(external_perimeter_speed); OPT_PTR(external_perimeters_first); @@ -1109,6 +1109,11 @@ class SLAPrintObjectConfig : public StaticPrintConfig public: ConfigOptionFloat layer_height; + //Number of the layers needed for the exposure time fade [3;20] + ConfigOptionInt faded_layers /*= 10*/; + + ConfigOptionFloat slice_closing_radius; + // Enabling or disabling support creation ConfigOptionBool supports_enable; @@ -1153,9 +1158,8 @@ public: ConfigOptionFloat support_object_elevation /*= 5.0*/; /////// Following options influence automatic support points placement: - ConfigOptionInt support_density_at_horizontal; - ConfigOptionInt support_density_at_45; - ConfigOptionFloat support_minimal_z; + ConfigOptionInt support_points_density_relative; + ConfigOptionFloat support_points_minimal_distance; // Now for the base pool (pad) ///////////////////////////////////////////// @@ -1175,10 +1179,15 @@ public: // The smoothing radius of the pad edges ConfigOptionFloat pad_edge_radius /*= 1*/; + // The slope of the pad wall... + ConfigOptionFloat pad_wall_slope; + protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { OPT_PTR(layer_height); + OPT_PTR(faded_layers); + OPT_PTR(slice_closing_radius); OPT_PTR(supports_enable); OPT_PTR(support_head_front_diameter); OPT_PTR(support_head_penetration); @@ -1191,15 +1200,15 @@ protected: OPT_PTR(support_base_height); OPT_PTR(support_critical_angle); OPT_PTR(support_max_bridge_length); - OPT_PTR(support_density_at_horizontal); - OPT_PTR(support_density_at_45); - OPT_PTR(support_minimal_z); + OPT_PTR(support_points_density_relative); + OPT_PTR(support_points_minimal_distance); OPT_PTR(support_object_elevation); OPT_PTR(pad_enable); OPT_PTR(pad_wall_thickness); OPT_PTR(pad_wall_height); OPT_PTR(pad_max_merge_distance); OPT_PTR(pad_edge_radius); + OPT_PTR(pad_wall_slope); } }; @@ -1236,6 +1245,9 @@ public: ConfigOptionInt display_pixels_y; ConfigOptionEnum display_orientation; ConfigOptionFloats printer_correction; + ConfigOptionFloat fast_tilt_time; + ConfigOptionFloat slow_tilt_time; + ConfigOptionFloat area_fill; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { @@ -1248,6 +1260,9 @@ protected: OPT_PTR(display_pixels_y); OPT_PTR(display_orientation); OPT_PTR(printer_correction); + OPT_PTR(fast_tilt_time); + OPT_PTR(slow_tilt_time); + OPT_PTR(area_fill); } }; diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 5cfb55217..df9446cf5 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -14,6 +14,17 @@ namespace Slic3r { +// Used for addressing parameters of FilePrinter::set_statistics() +enum ePrintStatistics +{ + psUsedMaterial = 0, + psNumFade, + psNumSlow, + psNumFast, + + psCnt +}; + enum class FilePrinterFormat { SLA_PNGZIP, SVG @@ -118,32 +129,37 @@ template<> class FilePrinter double m_layer_height = .0; Raster::Origin m_o = Raster::Origin::TOP_LEFT; + double m_used_material = 0.0; + int m_cnt_fade_layers = 0; + int m_cnt_slow_layers = 0; + int m_cnt_fast_layers = 0; + std::string createIniContent(const std::string& projectname) { - double layer_height = m_layer_height; +// double layer_height = m_layer_height; using std::string; using std::to_string; auto expt_str = to_string(m_exp_time_s); auto expt_first_str = to_string(m_exp_time_first_s); - auto stepnum_str = to_string(static_cast(800*layer_height)); - auto layerh_str = to_string(layer_height); +// auto stepnum_str = to_string(static_cast(800*layer_height)); + auto layerh_str = to_string(m_layer_height); + + const std::string cnt_fade_layers = to_string(m_cnt_fade_layers); + const std::string cnt_slow_layers = to_string(m_cnt_slow_layers); + const std::string cnt_fast_layers = to_string(m_cnt_fast_layers); + const std::string used_material = to_string(m_used_material); return string( "action = print\n" "jobDir = ") + projectname + "\n" + "expTime = " + expt_str + "\n" "expTimeFirst = " + expt_first_str + "\n" - "stepNum = " + stepnum_str + "\n" - "wifiOn = 1\n" - "tiltSlow = 60\n" - "tiltFast = 15\n" - "numFade = 10\n" - "startdelay = 0\n" + "numFade = " + cnt_fade_layers + "\n" "layerHeight = " + layerh_str + "\n" - "noteInfo = " - "expTime="+expt_str+"+resinType=generic+layerHeight=" - +layerh_str+"+printer=DWARF3\n"; + "usedMaterial = " + used_material + "\n" + "numSlow = " + cnt_slow_layers + "\n" + "numFast = " + cnt_fast_layers + "\n"; } public: @@ -277,6 +293,17 @@ public: out.close(); m_layers_rst[i].first.reset(); } + + void set_statistics(const std::vector statistics) + { + if (statistics.size() != psCnt) + return; + + m_used_material = statistics[psUsedMaterial]; + m_cnt_fade_layers = int(statistics[psNumFade]); + m_cnt_slow_layers = int(statistics[psNumSlow]); + m_cnt_fast_layers = int(statistics[psNumFast]); + } }; } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d168b37e8..66081bb8a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -482,7 +482,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector PrintObject::_slice_volumes(const std::vector &z, const Print *print = this->print(); auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); mslicer.init(&mesh, callback); - mslicer.slice(z, &layers, callback); + mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); m_print->throw_if_canceled(); } } diff --git a/src/libslic3r/SLA/SLAAutoSupports.cpp b/src/libslic3r/SLA/SLAAutoSupports.cpp index 98313be3f..e99ed111e 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.cpp +++ b/src/libslic3r/SLA/SLAAutoSupports.cpp @@ -1,47 +1,23 @@ #include "igl/random_points_on_mesh.h" #include "igl/AABB.h" +#include + #include "SLAAutoSupports.hpp" #include "Model.hpp" #include "ExPolygon.hpp" #include "SVG.hpp" #include "Point.hpp" #include "ClipperUtils.hpp" +#include "Tesselate.hpp" +#include "libslic3r.h" #include #include namespace Slic3r { -SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, const std::vector& heights, - const Config& config, std::function throw_on_cancel) -: m_config(config), m_V(emesh.V()), m_F(emesh.F()), m_throw_on_cancel(throw_on_cancel) -{ - // FIXME: It might be safer to get rid of the rand() calls altogether, because it is probably - // not always thread-safe and can be slow if it is. - srand(time(NULL)); // rand() is used by igl::random_point_on_mesh - - // Find all separate islands that will need support. The coord_t number denotes height - // of a point just below the mesh (so that we can later project the point precisely - // on the mesh by raycasting (done by igl) and not risking we will place the point inside). - std::vector> islands = find_islands(slices, heights); - - // Uniformly cover each of the islands with support points. - for (const auto& island : islands) { - std::vector points = uniformly_cover(island); - m_throw_on_cancel(); - project_upward_onto_mesh(points); - m_output.insert(m_output.end(), points.begin(), points.end()); - m_throw_on_cancel(); - } - - // We are done with the islands. Let's sprinkle the rest of the mesh. - // The function appends to m_output. - sprinkle_mesh(mesh); -} - - -float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2) +/*float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2) { n1.normalize(); n2.normalize(); @@ -59,115 +35,6 @@ float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3 } -void SLAAutoSupports::sprinkle_mesh(const TriangleMesh& mesh) -{ - std::vector points; - // Loads the ModelObject raw_mesh and transforms it by first instance's transformation matrix (disregarding translation). - // Instances only differ in z-rotation, so it does not matter which of them will be used for the calculation. - // The supports point will be calculated on this mesh (so scaling ang vertical direction is correctly accounted for). - // Results will be inverse-transformed to raw_mesh coordinates. - //TriangleMesh mesh = m_model_object.raw_mesh(); - //Transform3d transformation_matrix = m_model_object.instances[0]->get_matrix(true/*dont_translate*/); - //mesh.transform(transformation_matrix); - - // Check that the object is thick enough to produce any support points - BoundingBoxf3 bb = mesh.bounding_box(); - if (bb.size()(2) < m_config.minimal_z) - return; - - // All points that we curretly have must be transformed too, so distance to them is correcly calculated. - //for (Vec3f& point : m_model_object.sla_support_points) - // point = transformation_matrix.cast() * point; - - - // In order to calculate distance to already placed points, we must keep know which facet the point lies on. - std::vector facets_normals; - - // Only points belonging to islands were added so far - they all lie on horizontal surfaces: - for (unsigned int i=0; i aabb; - aabb.init(V, F); - for (unsigned int i=0; i dump; - Eigen::MatrixXf query_point = m_model_object.sla_support_points[i]; - aabb.squared_distance(V, F, query_point, facet_idx, dump); - Vec3f a1 = V.row(F(facet_idx,1)) - V.row(F(facet_idx,0)); - Vec3f a2 = V.row(F(facet_idx,2)) - V.row(F(facet_idx,0)); - Vec3f normal = a1.cross(a2); - normal.normalize(); - facets_normals.push_back(normal); - }*/ - - // New potential support point is randomly generated on the mesh and distance to all already placed points is calculated. - // In case it is never smaller than certain limit (depends on the new point's facet normal), the point is accepted. - // The process stops after certain number of points is refused in a row. - Vec3d point; - Vec3d normal; - int added_points = 0; - int refused_points = 0; - const int refused_limit = 30; - // Angle at which the density reaches zero: - const float threshold_angle = std::min(M_PI_2, M_PI_4 * acos(0.f/m_config.density_at_horizontal) / acos(m_config.density_at_45/m_config.density_at_horizontal)); - - size_t cancel_test_cntr = 0; - while (refused_points < refused_limit) { - if (++ cancel_test_cntr == 500) { - // Don't call the cancellation routine too often as the multi-core cache synchronization - // may be pretty expensive. - m_throw_on_cancel(); - cancel_test_cntr = 0; - } - // Place a random point on the mesh and calculate corresponding facet's normal: - Eigen::VectorXi FI; - Eigen::MatrixXd B; - igl::random_points_on_mesh(1, m_V, m_F, B, FI); - point = B(0,0)*m_V.row(m_F(FI(0),0)) + - B(0,1)*m_V.row(m_F(FI(0),1)) + - B(0,2)*m_V.row(m_F(FI(0),2)); - if (point(2) - bb.min(2) < m_config.minimal_z) - continue; - - Vec3d a1 = m_V.row(m_F(FI(0),1)) - m_V.row(m_F(FI(0),0)); - Vec3d a2 = m_V.row(m_F(FI(0),2)) - m_V.row(m_F(FI(0),0)); - normal = a1.cross(a2); - normal.normalize(); - - // calculate angle between the normal and vertical: - float angle = angle_from_normal(normal.cast()); - if (angle > threshold_angle) - continue; - - const float limit = distance_limit(angle); - bool add_it = true; - for (unsigned int i=0; i()); - facets_normals.push_back(normal); - ++added_points; - refused_points = 0; - } - } - - m_output.insert(m_output.end(), points.begin(), points.end()); - - // Now transform all support points to mesh coordinates: - //for (Vec3f& point : m_model_object.sla_support_points) - // point = transformation_matrix.inverse().cast() * point; -} - - - float SLAAutoSupports::get_required_density(float angle) const { // calculation would be density_0 * cos(angle). To provide one more degree of freedom, we will scale the angle @@ -179,10 +46,473 @@ float SLAAutoSupports::get_required_density(float angle) const float SLAAutoSupports::distance_limit(float angle) const { return 1./(2.4*get_required_density(angle)); +}*/ + +SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, const std::vector& heights, + const Config& config, std::function throw_on_cancel) +: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel) +{ + process(slices, heights); + project_onto_mesh(m_output); +} + +void SLAAutoSupports::project_onto_mesh(std::vector& points) const +{ + // The function makes sure that all the points are really exactly placed on the mesh. + igl::Hit hit_up{0, 0, 0.f, 0.f, 0.f}; + igl::Hit hit_down{0, 0, 0.f, 0.f, 0.f}; + + // Use a reasonable granularity to account for the worker thread synchronization cost. + tbb::parallel_for(tbb::blocked_range(0, points.size(), 64), + [this, &points](const tbb::blocked_range& range) { + for (size_t point_id = range.begin(); point_id < range.end(); ++ point_id) { + if ((point_id % 16) == 0) + // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves. + m_throw_on_cancel(); + Vec3f& p = points[point_id].pos; + // Project the point upward and downward and choose the closer intersection with the mesh. + //bool up = igl::ray_mesh_intersect(p.cast(), Vec3f(0., 0., 1.), m_V, m_F, hit_up); + //bool down = igl::ray_mesh_intersect(p.cast(), Vec3f(0., 0., -1.), m_V, m_F, hit_down); + + sla::EigenMesh3D::hit_result hit_up = m_emesh.query_ray_hit(p.cast(), Vec3d(0., 0., 1.)); + sla::EigenMesh3D::hit_result hit_down = m_emesh.query_ray_hit(p.cast(), Vec3d(0., 0., -1.)); + + bool up = hit_up.face() != -1; + bool down = hit_down.face() != -1; + + if (!up && !down) + continue; + + sla::EigenMesh3D::hit_result& hit = (!down || (hit_up.distance() < hit_down.distance())) ? hit_up : hit_down; + //int fid = hit.face(); + //Vec3f bc(1-hit.u-hit.v, hit.u, hit.v); + //p = (bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2))).cast(); + + p = p + (hit.distance() * hit.direction()).cast(); + } + }); +} + +static std::vector make_layers( + const std::vector& slices, const std::vector& heights, + std::function throw_on_cancel) +{ + assert(slices.size() == heights.size()); + + // Allocate empty layers. + std::vector layers; + layers.reserve(slices.size()); + for (size_t i = 0; i < slices.size(); ++ i) + layers.emplace_back(i, heights[i]); + + // FIXME: calculate actual pixel area from printer config: + //const float pixel_area = pow(wxGetApp().preset_bundle->project_config.option("display_width") / wxGetApp().preset_bundle->project_config.option("display_pixels_x"), 2.f); // + const float pixel_area = pow(0.047f, 2.f); + + // Use a reasonable granularity to account for the worker thread synchronization cost. + tbb::parallel_for(tbb::blocked_range(0, layers.size(), 32), + [&layers, &slices, &heights, pixel_area, throw_on_cancel](const tbb::blocked_range& range) { + for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { + if ((layer_id % 8) == 0) + // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves. + throw_on_cancel(); + SLAAutoSupports::MyLayer &layer = layers[layer_id]; + const ExPolygons &islands = slices[layer_id]; + //FIXME WTF? + const float height = (layer_id>2 ? heights[layer_id-3] : heights[0]-(heights[1]-heights[0])); + layer.islands.reserve(islands.size()); + for (const ExPolygon &island : islands) { + float area = float(island.area() * SCALING_FACTOR * SCALING_FACTOR); + if (area >= pixel_area) + //FIXME this is not a correct centroid of a polygon with holes. + layer.islands.emplace_back(layer, island, get_extents(island.contour), Slic3r::unscale(island.contour.centroid()).cast(), area, height); + } + } + }); + + // Calculate overlap of successive layers. Link overlapping islands. + tbb::parallel_for(tbb::blocked_range(1, layers.size(), 8), + [&layers, &heights, throw_on_cancel](const tbb::blocked_range& range) { + for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) { + if ((layer_id % 2) == 0) + // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves. + throw_on_cancel(); + SLAAutoSupports::MyLayer &layer_above = layers[layer_id]; + SLAAutoSupports::MyLayer &layer_below = layers[layer_id - 1]; + //FIXME WTF? + const float height = (layer_id>2 ? heights[layer_id-3] : heights[0]-(heights[1]-heights[0])); + const float layer_height = (layer_id!=0 ? heights[layer_id]-heights[layer_id-1] : heights[0]); + const float safe_angle = 5.f * (float(M_PI)/180.f); // smaller number - less supports + const float between_layers_offset = float(scale_(layer_height / std::tan(safe_angle))); + const float slope_angle = 75.f * (float(M_PI)/180.f); // smaller number - less supports + const float slope_offset = float(scale_(layer_height / std::tan(slope_angle))); + //FIXME This has a quadratic time complexity, it will be excessively slow for many tiny islands. + for (SLAAutoSupports::Structure &top : layer_above.islands) { + for (SLAAutoSupports::Structure &bottom : layer_below.islands) { + float overlap_area = top.overlap_area(bottom); + if (overlap_area > 0) { + top.islands_below.emplace_back(&bottom, overlap_area); + bottom.islands_above.emplace_back(&top, overlap_area); + } + } + if (! top.islands_below.empty()) { + Polygons top_polygons = to_polygons(*top.polygon); + Polygons bottom_polygons = top.polygons_below(); + top.overhangs = diff_ex(top_polygons, bottom_polygons); + if (! top.overhangs.empty()) { + top.overhangs_area = 0.f; + std::vector> expolys_with_areas; + for (ExPolygon &ex : top.overhangs) { + float area = float(ex.area()); + expolys_with_areas.emplace_back(&ex, area); + top.overhangs_area += area; + } + std::sort(expolys_with_areas.begin(), expolys_with_areas.end(), + [](const std::pair &p1, const std::pair &p2) + { return p1.second > p2.second; }); + ExPolygons overhangs_sorted; + for (auto &p : expolys_with_areas) + overhangs_sorted.emplace_back(std::move(*p.first)); + top.overhangs = std::move(overhangs_sorted); + top.overhangs_area *= float(SCALING_FACTOR * SCALING_FACTOR); + top.overhangs_slopes = diff_ex(top_polygons, offset(bottom_polygons, slope_offset)); + top.dangling_areas = diff_ex(top_polygons, offset(bottom_polygons, between_layers_offset)); + } + } + } + } + }); + + return layers; +} + +void SLAAutoSupports::process(const std::vector& slices, const std::vector& heights) +{ +#ifdef SLA_AUTOSUPPORTS_DEBUG + std::vector> islands; +#endif /* SLA_AUTOSUPPORTS_DEBUG */ + + std::vector layers = make_layers(slices, heights, m_throw_on_cancel); + + PointGrid3D point_grid; + point_grid.cell_size = Vec3f(10.f, 10.f, 10.f); + + for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) { + SLAAutoSupports::MyLayer *layer_top = &layers[layer_id]; + SLAAutoSupports::MyLayer *layer_bottom = (layer_id > 0) ? &layers[layer_id - 1] : nullptr; + std::vector support_force_bottom; + if (layer_bottom != nullptr) { + support_force_bottom.assign(layer_bottom->islands.size(), 0.f); + for (size_t i = 0; i < layer_bottom->islands.size(); ++ i) + support_force_bottom[i] = layer_bottom->islands[i].supports_force_total(); + } + for (Structure &top : layer_top->islands) + for (Structure::Link &bottom_link : top.islands_below) { + Structure &bottom = *bottom_link.island; + float centroids_dist = (bottom.centroid - top.centroid).norm(); + // Penalization resulting from centroid offset: +// bottom.supports_force *= std::min(1.f, 1.f - std::min(1.f, (1600.f * layer_height) * centroids_dist * centroids_dist / bottom.area)); + float &support_force = support_force_bottom[&bottom - layer_bottom->islands.data()]; +//FIXME this condition does not reflect a bifurcation into a one large island and one tiny island well, it incorrectly resets the support force to zero. +// One should rather work with the overlap area vs overhang area. +// support_force *= std::min(1.f, 1.f - std::min(1.f, 0.1f * centroids_dist * centroids_dist / bottom.area)); + // Penalization resulting from increasing polygon area: + support_force *= std::min(1.f, 20.f * bottom.area / top.area); + } + // Let's assign proper support force to each of them: + if (layer_id > 0) { + for (Structure &below : layer_bottom->islands) { + float below_support_force = support_force_bottom[&below - layer_bottom->islands.data()]; + float above_overlap_area = 0.f; + for (Structure::Link &above_link : below.islands_above) + above_overlap_area += above_link.overlap_area; + for (Structure::Link &above_link : below.islands_above) + above_link.island->supports_force_inherited += below_support_force * above_link.overlap_area / above_overlap_area; + } + } + // Now iterate over all polygons and append new points if needed. + for (Structure &s : layer_top->islands) { + // Penalization resulting from large diff from the last layer: +// s.supports_force_inherited /= std::max(1.f, (layer_height / 0.3f) * e_area / s.area); + s.supports_force_inherited /= std::max(1.f, 0.17f * (s.overhangs_area) / s.area); + + float force_deficit = s.support_force_deficit(m_config.tear_pressure()); + if (s.islands_below.empty()) { // completely new island - needs support no doubt + uniformly_cover({ *s.polygon }, s, point_grid, true); + } else if (! s.dangling_areas.empty()) { + // Let's see if there's anything that overlaps enough to need supports: + // What we now have in polygons needs support, regardless of what the forces are, so we can add them. + //FIXME is it an island point or not? Vojtech thinks it is. + uniformly_cover(s.dangling_areas, s, point_grid); + } else if (! s.overhangs_slopes.empty()) { + //FIXME add the support force deficit as a parameter, only cover until the defficiency is covered. + uniformly_cover(s.overhangs_slopes, s, point_grid); + } + } + + m_throw_on_cancel(); + +#ifdef SLA_AUTOSUPPORTS_DEBUG + /*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i); + output_expolygons(expolys_top, "top" + layer_num_str + ".svg"); + output_expolygons(diff, "diff" + layer_num_str + ".svg"); + if (!islands.empty()) + output_expolygons(islands, "islands" + layer_num_str + ".svg");*/ +#endif /* SLA_AUTOSUPPORTS_DEBUG */ + } +} + +std::vector sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng) +{ + // Triangulate the polygon with holes into triplets of 3D points. + std::vector triangles = Slic3r::triangulate_expolygon_2f(expoly); + + std::vector out; + if (! triangles.empty()) + { + // Calculate area of each triangle. + std::vector areas; + areas.reserve(triangles.size() / 3); + for (size_t i = 0; i < triangles.size(); ) { + const Vec2f &a = triangles[i ++]; + const Vec2f v1 = triangles[i ++] - a; + const Vec2f v2 = triangles[i ++] - a; + areas.emplace_back(0.5f * std::abs(cross2(v1, v2))); + if (i != 3) + // Prefix sum of the areas. + areas.back() += areas[areas.size() - 2]; + } + + size_t num_samples = size_t(ceil(areas.back() * samples_per_mm2)); + std::uniform_real_distribution<> random_triangle(0., double(areas.back())); + std::uniform_real_distribution<> random_float(0., 1.); + for (size_t i = 0; i < num_samples; ++ i) { + double r = random_triangle(rng); + size_t idx_triangle = std::min(std::upper_bound(areas.begin(), areas.end(), (float)r) - areas.begin(), areas.size() - 1) * 3; + // Select a random point on the triangle. + double u = float(sqrt(random_float(rng))); + double v = float(random_float(rng)); + const Vec2f &a = triangles[idx_triangle ++]; + const Vec2f &b = triangles[idx_triangle++]; + const Vec2f &c = triangles[idx_triangle]; + const Vec2f x = a * (1.f - u) + b * (u * (1.f - v)) + c * (v * u); + out.emplace_back(x); + } + } + return out; +} + +std::vector sample_expolygon_with_boundary(const ExPolygon &expoly, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng) +{ + std::vector out = sample_expolygon(expoly, samples_per_mm2, rng); + double point_stepping_scaled = scale_(1.f) / samples_per_mm_boundary; + for (size_t i_contour = 0; i_contour <= expoly.holes.size(); ++ i_contour) { + const Polygon &contour = (i_contour == 0) ? expoly.contour : expoly.holes[i_contour - 1]; + const Points pts = contour.equally_spaced_points(point_stepping_scaled); + for (size_t i = 0; i < pts.size(); ++ i) + out.emplace_back(unscale(pts[i].x()), unscale(pts[i].y())); + } + return out; +} + +std::vector sample_expolygon_with_boundary(const ExPolygons &expolys, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng) +{ + std::vector out; + for (const ExPolygon &expoly : expolys) + append(out, sample_expolygon_with_boundary(expoly, samples_per_mm2, samples_per_mm_boundary, rng)); + return out; +} + +template +static inline std::vector poisson_disk_from_samples(const std::vector &raw_samples, float radius, REFUSE_FUNCTION refuse_function) +{ + Vec2f corner_min(std::numeric_limits::max(), std::numeric_limits::max()); + for (const Vec2f &pt : raw_samples) { + corner_min.x() = std::min(corner_min.x(), pt.x()); + corner_min.y() = std::min(corner_min.y(), pt.y()); + } + + // Assign the raw samples to grid cells, sort the grid cells lexicographically. + struct RawSample { + Vec2f coord; + Vec2i cell_id; + }; + std::vector raw_samples_sorted; + RawSample sample; + for (const Vec2f &pt : raw_samples) { + sample.coord = pt; + sample.cell_id = ((pt - corner_min) / radius).cast(); + raw_samples_sorted.emplace_back(sample); + } + std::sort(raw_samples_sorted.begin(), raw_samples_sorted.end(), [](const RawSample &lhs, const RawSample &rhs) + { return lhs.cell_id.x() < rhs.cell_id.x() || (lhs.cell_id.x() == rhs.cell_id.x() && lhs.cell_id.y() < rhs.cell_id.y()); }); + + struct PoissonDiskGridEntry { + // Resulting output sample points for this cell: + enum { + max_positions = 4 + }; + Vec2f poisson_samples[max_positions]; + int num_poisson_samples = 0; + + // Index into raw_samples: + int first_sample_idx; + int sample_cnt; + }; + + struct CellIDHash { + std::size_t operator()(const Vec2i &cell_id) const { + return std::hash()(cell_id.x()) ^ std::hash()(cell_id.y() * 593); + } + }; + + // Map from cell IDs to hash_data. Each hash_data points to the range in raw_samples corresponding to that cell. + // (We could just store the samples in hash_data. This implementation is an artifact of the reference paper, which + // is optimizing for GPU acceleration that we haven't implemented currently.) + typedef std::unordered_map Cells; + Cells cells; + { + typename Cells::iterator last_cell_id_it; + Vec2i last_cell_id(-1, -1); + for (int i = 0; i < raw_samples_sorted.size(); ++ i) { + const RawSample &sample = raw_samples_sorted[i]; + if (sample.cell_id == last_cell_id) { + // This sample is in the same cell as the previous, so just increase the count. Cells are + // always contiguous, since we've sorted raw_samples_sorted by cell ID. + ++ last_cell_id_it->second.sample_cnt; + } else { + // This is a new cell. + PoissonDiskGridEntry data; + data.first_sample_idx = i; + data.sample_cnt = 1; + auto result = cells.insert({sample.cell_id, data}); + last_cell_id = sample.cell_id; + last_cell_id_it = result.first; + } + } + } + + const int max_trials = 5; + const float radius_squared = radius * radius; + for (int trial = 0; trial < max_trials; ++ trial) { + // Create sample points for each entry in cells. + for (auto &it : cells) { + const Vec2i &cell_id = it.first; + PoissonDiskGridEntry &cell_data = it.second; + // This cell's raw sample points start at first_sample_idx. On trial 0, try the first one. On trial 1, try first_sample_idx + 1. + int next_sample_idx = cell_data.first_sample_idx + trial; + if (trial >= cell_data.sample_cnt) + // There are no more points to try for this cell. + continue; + const RawSample &candidate = raw_samples_sorted[next_sample_idx]; + // See if this point conflicts with any other points in this cell, or with any points in + // neighboring cells. Note that it's possible to have more than one point in the same cell. + bool conflict = refuse_function(candidate.coord); + for (int i = -1; i < 2 && ! conflict; ++ i) { + for (int j = -1; j < 2; ++ j) { + const auto &it_neighbor = cells.find(cell_id + Vec2i(i, j)); + if (it_neighbor != cells.end()) { + const PoissonDiskGridEntry &neighbor = it_neighbor->second; + for (int i_sample = 0; i_sample < neighbor.num_poisson_samples; ++ i_sample) + if ((neighbor.poisson_samples[i_sample] - candidate.coord).squaredNorm() < radius_squared) { + conflict = true; + break; + } + } + } + } + if (! conflict) { + // Store the new sample. + assert(cell_data.num_poisson_samples < cell_data.max_positions); + if (cell_data.num_poisson_samples < cell_data.max_positions) + cell_data.poisson_samples[cell_data.num_poisson_samples ++] = candidate.coord; + } + } + } + + // Copy the results to the output. + std::vector out; + for (const auto& it : cells) + for (int i = 0; i < it.second.num_poisson_samples; ++ i) + out.emplace_back(it.second.poisson_samples[i]); + return out; +} + +void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island, bool just_one) +{ + //int num_of_points = std::max(1, (int)((island.area()*pow(SCALING_FACTOR, 2) * m_config.tear_pressure)/m_config.support_force)); + + const float support_force_deficit = structure.support_force_deficit(m_config.tear_pressure()); + if (support_force_deficit < 0) + return; + + // Number of newly added points. + const size_t poisson_samples_target = size_t(ceil(support_force_deficit / m_config.support_force())); + + const float density_horizontal = m_config.tear_pressure() / m_config.support_force(); + //FIXME why? + float poisson_radius = std::max(m_config.minimal_distance, 1.f / (5.f * density_horizontal)); +// const float poisson_radius = 1.f / (15.f * density_horizontal); + const float samples_per_mm2 = 30.f / (float(M_PI) * poisson_radius * poisson_radius); + // Minimum distance between samples, in 3D space. +// float min_spacing = poisson_radius / 3.f; + float min_spacing = poisson_radius; + + //FIXME share the random generator. The random generator may be not so cheap to initialize, also we don't want the random generator to be restarted for each polygon. + std::random_device rd; + std::mt19937 rng(rd()); + std::vector raw_samples = sample_expolygon_with_boundary(islands, samples_per_mm2, 5.f / poisson_radius, rng); + std::vector poisson_samples; + for (size_t iter = 0; iter < 4; ++ iter) { + poisson_samples = poisson_disk_from_samples(raw_samples, poisson_radius, + [&structure, &grid3d, min_spacing](const Vec2f &pos) { + return grid3d.collides_with(pos, &structure, min_spacing); + }); + if (poisson_samples.size() >= poisson_samples_target || m_config.minimal_distance > poisson_radius-EPSILON) + break; + float coeff = 0.5f; + if (poisson_samples.size() * 2 > poisson_samples_target) + coeff = float(poisson_samples.size()) / float(poisson_samples_target); + poisson_radius = std::max(m_config.minimal_distance, poisson_radius * coeff); + min_spacing = std::max(m_config.minimal_distance, min_spacing * coeff); + } + +#ifdef SLA_AUTOSUPPORTS_DEBUG + { + static int irun = 0; + Slic3r::SVG svg(debug_out_path("SLA_supports-uniformly_cover-%d.svg", irun ++), get_extents(islands)); + for (const ExPolygon &island : islands) + svg.draw(island); + for (const Vec2f &pt : raw_samples) + svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "red"); + for (const Vec2f &pt : poisson_samples) + svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "blue"); + } +#endif /* NDEBUG */ + +// assert(! poisson_samples.empty()); + if (poisson_samples_target < poisson_samples.size()) { + std::shuffle(poisson_samples.begin(), poisson_samples.end(), rng); + poisson_samples.erase(poisson_samples.begin() + poisson_samples_target, poisson_samples.end()); + } + for (const Vec2f &pt : poisson_samples) { + m_output.emplace_back(float(pt(0)), float(pt(1)), structure.height, 0.2f, is_new_island); + structure.supports_force_this_layer += m_config.support_force(); + grid3d.insert(pt, &structure); + } } #ifdef SLA_AUTOSUPPORTS_DEBUG -void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, std::string filename) const +void SLAAutoSupports::output_structures(const std::vector& structures) +{ + for (unsigned int i=0 ; i{*structures[i].polygon}, ss.str()); + } +} + +void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, const std::string &filename) { BoundingBox bb(Point(-30000000, -30000000), Point(30000000, 30000000)); Slic3r::SVG svg_cummulative(filename, bb); @@ -198,138 +528,6 @@ void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, std::string f svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05)); } } -#endif /* SLA_AUTOSUPPORTS_DEBUG */ - -std::vector> SLAAutoSupports::find_islands(const std::vector& slices, const std::vector& heights) const -{ - std::vector> islands; - - struct PointAccessor { - const Point* operator()(const Point &pt) const { return &pt; } - }; - typedef ClosestPointInRadiusLookup ClosestPointLookupType; - - for (unsigned int i = 0; i SLAAutoSupports::uniformly_cover(const std::pair& island) -{ - int num_of_points = std::max(1, (int)(island.first.area()*pow(SCALING_FACTOR, 2) * get_required_density(0))); - - // In case there is just one point to place, we'll place it into the polygon's centroid (unless it lies in a hole). - if (num_of_points == 1) { - Point out(island.first.contour.centroid()); - - for (const auto& hole : island.first.holes) - if (hole.contains(out)) - goto HOLE_HIT; - return std::vector{unscale(out(0), out(1), island.second)}; - } - -HOLE_HIT: - // In this case either the centroid lies in a hole, or there are multiple points - // to place. We will cover the island another way. - // For now we'll just place the points randomly not too close to the others. - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution<> dis(0., 1.); - - std::vector island_new_points; - const BoundingBox& bb = get_extents(island.first); - const int refused_limit = 30; - int refused_points = 0; - while (refused_points < refused_limit) { - Point out(bb.min(0) + bb.size()(0) * dis(gen), - bb.min(1) + bb.size()(1) * dis(gen)) ; - Vec3d unscaled_out = unscale(out(0), out(1), island.second); - bool add_it = true; - - if (!island.first.contour.contains(out)) - add_it = false; - else - for (const Polygon& hole : island.first.holes) - if (hole.contains(out)) - add_it = false; - - if (add_it) { - for (const Vec3d& p : island_new_points) { - if ((p - unscaled_out).squaredNorm() < distance_limit(0)) { - add_it = false; - ++refused_points; - break; - } - } - } - if (add_it) - island_new_points.emplace_back(unscaled_out); - } - return island_new_points; -} - -void SLAAutoSupports::project_upward_onto_mesh(std::vector& points) const -{ - Vec3f dir(0., 0., 1.); - igl::Hit hit{0, 0, 0.f, 0.f, 0.f}; - for (Vec3d& p : points) { - igl::ray_mesh_intersect(p.cast(), dir, m_V, m_F, hit); - int fid = hit.id; - Vec3f bc(1-hit.u-hit.v, hit.u, hit.v); - p = (bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2))).cast(); - } -} - +#endif } // namespace Slic3r diff --git a/src/libslic3r/SLA/SLAAutoSupports.hpp b/src/libslic3r/SLA/SLAAutoSupports.hpp index 311d7b0c7..5a758c2a6 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.hpp +++ b/src/libslic3r/SLA/SLAAutoSupports.hpp @@ -1,9 +1,12 @@ #ifndef SLAAUTOSUPPORTS_HPP_ #define SLAAUTOSUPPORTS_HPP_ +#include #include #include -#include +#include + +#include // #define SLA_AUTOSUPPORTS_DEBUG @@ -12,36 +15,188 @@ namespace Slic3r { class SLAAutoSupports { public: struct Config { - float density_at_horizontal; - float density_at_45; - float minimal_z; + float density_relative; + float minimal_distance; + /////////////// + inline float support_force() const { return 10.f / density_relative; } // a force one point can support (arbitrary force unit) + inline float tear_pressure() const { return 1.f; } // pressure that the display exerts (the force unit per mm2) }; - SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, - const std::vector& heights, const Config& config, std::function throw_on_cancel); - const std::vector& output() { return m_output; } + SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, + const std::vector& heights, const Config& config, std::function throw_on_cancel); + const std::vector& output() { return m_output; } -private: - std::vector m_output; - std::vector m_normals; - TriangleMesh mesh; - static float angle_from_normal(const stl_normal& normal) { return acos((-normal.normalized())(2)); } - float get_required_density(float angle) const; - float distance_limit(float angle) const; - static float approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2); - std::vector> find_islands(const std::vector& slices, const std::vector& heights) const; - void sprinkle_mesh(const TriangleMesh& mesh); - std::vector uniformly_cover(const std::pair& island); - void project_upward_onto_mesh(std::vector& points) const; + struct MyLayer; + struct Structure { + Structure(MyLayer &layer, const ExPolygon& poly, const BoundingBox &bbox, const Vec2f ¢roid, float area, float h) : + layer(&layer), polygon(&poly), bbox(bbox), centroid(centroid), area(area), height(h) #ifdef SLA_AUTOSUPPORTS_DEBUG - void output_expolygons(const ExPolygons& expolys, std::string filename) const; + , unique_id(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) +#endif /* SLA_AUTOSUPPORTS_DEBUG */ + {} + MyLayer *layer; + const ExPolygon* polygon = nullptr; + const BoundingBox bbox; + const Vec2f centroid = Vec2f::Zero(); + const float area = 0.f; + float height = 0; + // How well is this ExPolygon held to the print base? + // Positive number, the higher the better. + float supports_force_this_layer = 0.f; + float supports_force_inherited = 0.f; + float supports_force_total() const { return this->supports_force_this_layer + this->supports_force_inherited; } +#ifdef SLA_AUTOSUPPORTS_DEBUG + std::chrono::milliseconds unique_id; #endif /* SLA_AUTOSUPPORTS_DEBUG */ + struct Link { + Link(Structure *island, float overlap_area) : island(island), overlap_area(overlap_area) {} + Structure *island; + float overlap_area; + }; + +#ifdef NDEBUG + // In release mode, use the optimized container. + boost::container::small_vector islands_above; + boost::container::small_vector islands_below; +#else + // In debug mode, use the standard vector, which is well handled by debugger visualizer. + std::vector islands_above; + std::vector islands_below; +#endif + // Overhangs, that are dangling considerably. + ExPolygons dangling_areas; + // Complete overhands. + ExPolygons overhangs; + // Overhangs, where the surface must slope. + ExPolygons overhangs_slopes; + float overhangs_area; + + bool overlaps(const Structure &rhs) const { + return this->bbox.overlap(rhs.bbox) && (this->polygon->overlaps(*rhs.polygon) || rhs.polygon->overlaps(*this->polygon)); + } + float overlap_area(const Structure &rhs) const { + double out = 0.; + if (this->bbox.overlap(rhs.bbox)) { + Polygons polys = intersection(to_polygons(*this->polygon), to_polygons(*rhs.polygon), false); + for (const Polygon &poly : polys) + out += poly.area(); + } + return float(out); + } + float area_below() const { + float area = 0.f; + for (const Link &below : this->islands_below) + area += below.island->area; + return area; + } + Polygons polygons_below() const { + size_t cnt = 0; + for (const Link &below : this->islands_below) + cnt += 1 + below.island->polygon->holes.size(); + Polygons out; + out.reserve(cnt); + for (const Link &below : this->islands_below) { + out.emplace_back(below.island->polygon->contour); + append(out, below.island->polygon->holes); + } + return out; + } + ExPolygons expolygons_below() const { + ExPolygons out; + out.reserve(this->islands_below.size()); + for (const Link &below : this->islands_below) + out.emplace_back(*below.island->polygon); + return out; + } + // Positive deficit of the supports. If negative, this area is well supported. If positive, more supports need to be added. + float support_force_deficit(const float tear_pressure) const { return this->area * tear_pressure - this->supports_force_total(); } + }; + + struct MyLayer { + MyLayer(const size_t layer_id, coordf_t print_z) : layer_id(layer_id), print_z(print_z) {} + size_t layer_id; + coordf_t print_z; + std::vector islands; + }; + + struct RichSupportPoint { + Vec3f position; + Structure *island; + }; + + struct PointGrid3D { + struct GridHash { + std::size_t operator()(const Vec3i &cell_id) const { + return std::hash()(cell_id.x()) ^ std::hash()(cell_id.y() * 593) ^ std::hash()(cell_id.z() * 7919); + } + }; + typedef std::unordered_multimap Grid; + + Vec3f cell_size; + Grid grid; + + Vec3i cell_id(const Vec3f &pos) { + return Vec3i(int(floor(pos.x() / cell_size.x())), + int(floor(pos.y() / cell_size.y())), + int(floor(pos.z() / cell_size.z()))); + } + + void insert(const Vec2f &pos, Structure *island) { + RichSupportPoint pt; + pt.position = Vec3f(pos.x(), pos.y(), float(island->layer->print_z)); + pt.island = island; + grid.emplace(cell_id(pt.position), pt); + } + + bool collides_with(const Vec2f &pos, Structure *island, float radius) { + Vec3f pos3d(pos.x(), pos.y(), float(island->layer->print_z)); + Vec3i cell = cell_id(pos3d); + std::pair it_pair = grid.equal_range(cell); + if (collides_with(pos3d, radius, it_pair.first, it_pair.second)) + return true; + for (int i = -1; i < 2; ++ i) + for (int j = -1; j < 2; ++ j) + for (int k = -1; k < 1; ++ k) { + if (i == 0 && j == 0 && k == 0) + continue; + it_pair = grid.equal_range(cell + Vec3i(i, j, k)); + if (collides_with(pos3d, radius, it_pair.first, it_pair.second)) + return true; + } + return false; + } + + private: + bool collides_with(const Vec3f &pos, float radius, Grid::const_iterator it_begin, Grid::const_iterator it_end) { + for (Grid::const_iterator it = it_begin; it != it_end; ++ it) { + float dist2 = (it->second.position - pos).squaredNorm(); + if (dist2 < radius * radius) + return true; + } + return false; + } + }; + +private: + std::vector m_output; + SLAAutoSupports::Config m_config; + + float m_supports_force_total = 0.f; + + void process(const std::vector& slices, const std::vector& heights); + void uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island = false, bool just_one = false); + void project_onto_mesh(std::vector& points) const; + +#ifdef SLA_AUTOSUPPORTS_DEBUG + static void output_expolygons(const ExPolygons& expolys, const std::string &filename); + static void output_structures(const std::vector &structures); +#endif // SLA_AUTOSUPPORTS_DEBUG + std::function m_throw_on_cancel; - const Eigen::MatrixXd& m_V; - const Eigen::MatrixXi& m_F; + const sla::EigenMesh3D& m_emesh; }; diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index a235d52ba..6fd218402 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -4,78 +4,177 @@ #include "boost/log/trivial.hpp" #include "SLABoostAdapter.hpp" #include "ClipperUtils.hpp" +#include "Tesselate.hpp" +// For debugging: +//#include +//#include //#include "SVG.hpp" -//#include "benchmark.h" namespace Slic3r { namespace sla { -/// Convert the triangulation output to an intermediate mesh. -Contour3D convert(const Polygons& triangles, coord_t z, bool dir) { - - Pointf3s points; - points.reserve(3*triangles.size()); - Indices indices; - indices.reserve(points.size()); - - for(auto& tr : triangles) { - auto c = coord_t(points.size()), b = c++, a = c++; - if(dir) indices.emplace_back(a, b, c); - else indices.emplace_back(c, b, a); - for(auto& p : tr.points) { - points.emplace_back(unscale(x(p), y(p), z)); - } - } - - return {points, indices}; -} - -Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling, - double floor_z_mm, double ceiling_z_mm, - ThrowOnCancel thr) +/// This function will return a triangulation of a sheet connecting an upper +/// and a lower plate given as input polygons. It will not triangulate the +/// plates themselves only the sheet. The caller has to specify the lower and +/// upper z levels in world coordinates as well as the offset difference +/// between the sheets. If the lower_z_mm is higher than upper_z_mm or the +/// offset difference is negative, the resulting triangle orientation will be +/// reversed. +/// +/// IMPORTANT: This is not a universal triangulation algorithm. It assumes +/// that the lower and upper polygons are offsetted versions of the same +/// original polygon. In general, it assumes that one of the polygons is +/// completely inside the other. The offset difference is the reference +/// distance from the inner polygon's perimeter to the outer polygon's +/// perimeter. The real distance will be variable as the clipper offset has +/// different strategies (rounding, etc...). This algorithm should have +/// O(2n + 3m) complexity where n is the number of upper vertices and m is the +/// number of lower vertices. +Contour3D walls(const Polygon& lower, const Polygon& upper, + double lower_z_mm, double upper_z_mm, + double offset_difference_mm, ThrowOnCancel thr) { - using std::transform; using std::back_inserter; - - ExPolygon poly; - poly.contour.points = floor_plate.contour.points; - poly.holes.emplace_back(ceiling.contour); - auto& h = poly.holes.front(); - std::reverse(h.points.begin(), h.points.end()); - Polygons tri = triangulate(poly); - Contour3D ret; - ret.points.reserve(tri.size() * 3); - double fz = floor_z_mm; - double cz = ceiling_z_mm; - auto& rp = ret.points; - auto& rpi = ret.indices; - ret.indices.reserve(tri.size() * 3); + if(upper.points.size() < 3 || lower.size() < 3) return ret; - coord_t idx = 0; + // The concept of the algorithm is relatively simple. It will try to find + // the closest vertices from the upper and the lower polygon and use those + // as starting points. Then it will create the triangles sequentially using + // an edge from the upper polygon and a vertex from the lower or vice versa, + // depending on the resulting triangle's quality. + // The quality is measured by a scalar value. So far it looks like it is + // enough to derive it from the slope of the triangle's two edges connecting + // the upper and the lower part. A reference slope is calculated from the + // height and the offset difference. - auto hlines = h.lines(); - auto is_upper = [&hlines](const Point& p) { - return std::any_of(hlines.begin(), hlines.end(), - [&p](const Line& l) { - return l.distance_to(p) < mm(1e-6); - }); + // Offset in the index array for the ceiling + const auto offs = upper.points.size(); + + // Shorthand for the vertex arrays + auto& upoints = upper.points, &lpoints = lower.points; + auto& rpts = ret.points; auto& rfaces = ret.indices; + + // If the Z levels are flipped, or the offset difference is negative, we + // will interpret that as the triangles normals should be inverted. + bool inverted = upper_z_mm < lower_z_mm || offset_difference_mm < 0; + + // Copy the points into the mesh, convert them from 2D to 3D + rpts.reserve(upoints.size() + lpoints.size()); + rfaces.reserve(2*upoints.size() + 2*lpoints.size()); + const double sf = SCALING_FACTOR; + for(auto& p : upoints) rpts.emplace_back(p.x()*sf, p.y()*sf, upper_z_mm); + for(auto& p : lpoints) rpts.emplace_back(p.x()*sf, p.y()*sf, lower_z_mm); + + // Create pointing indices into vertex arrays. u-upper, l-lower + size_t uidx = 0, lidx = offs, unextidx = 1, lnextidx = offs + 1; + + // Simple squared distance calculation. + auto distfn = [](const Vec3d& p1, const Vec3d& p2) { + auto p = p1 - p2; return p.transpose() * p; }; - std::for_each(tri.begin(), tri.end(), - [&rp, &rpi, thr, &idx, is_upper, fz, cz](const Polygon& pp) - { - thr(); // may throw if cancellation was requested + // We need to find the closest point on lower polygon to the first point on + // the upper polygon. These will be our starting points. + double distmin = std::numeric_limits::max(); + for(size_t l = lidx; l < rpts.size(); ++l) { + thr(); + double d = distfn(rpts[l], rpts[uidx]); + if(d < distmin) { lidx = l; distmin = d; } + } - for(auto& p : pp.points) - if(is_upper(p)) - rp.emplace_back(unscale(x(p), y(p), mm(cz))); - else rp.emplace_back(unscale(x(p), y(p), mm(fz))); + // Set up lnextidx to be ahead of lidx in cyclic mode + lnextidx = lidx + 1; + if(lnextidx == rpts.size()) lnextidx = offs; - coord_t a = idx++, b = idx++, c = idx++; - if(fz > cz) rpi.emplace_back(c, b, a); - else rpi.emplace_back(a, b, c); - }); + // This will be the flip switch to toggle between upper and lower triangle + // creation mode + enum class Proceed { + UPPER, // A segment from the upper polygon and one vertex from the lower + LOWER // A segment from the lower polygon and one vertex from the upper + } proceed = Proceed::UPPER; + + // Flags to help evaluating loop termination. + bool ustarted = false, lstarted = false; + + // The variables for the fitness values, one for the actual and one for the + // previous. + double current_fit = 0, prev_fit = 0; + + // Every triangle of the wall has two edges connecting the upper plate with + // the lower plate. From the length of these two edges and the zdiff we + // can calculate the momentary squared offset distance at a particular + // position on the wall. The average of the differences from the reference + // (squared) offset distance will give us the driving fitness value. + const double offsdiff2 = std::pow(offset_difference_mm, 2); + const double zdiff2 = std::pow(upper_z_mm - lower_z_mm, 2); + + // Mark the current vertex iterator positions. If the iterators return to + // the same position, the loop can be terminated. + size_t uendidx = uidx, lendidx = lidx; + + do { thr(); // check throw if canceled + + prev_fit = current_fit; + + switch(proceed) { // proceed depending on the current state + case Proceed::UPPER: + if(!ustarted || uidx != uendidx) { // there are vertices remaining + // Get the 3D vertices in order + const Vec3d& p_up1 = rpts[size_t(uidx)]; + const Vec3d& p_low = rpts[size_t(lidx)]; + const Vec3d& p_up2 = rpts[size_t(unextidx)]; + + // Calculate fitness: the average of the two connecting edges + double a = offsdiff2 - (distfn(p_up1, p_low) - zdiff2); + double b = offsdiff2 - (distfn(p_up2, p_low) - zdiff2); + current_fit = (std::abs(a) + std::abs(b)) / 2; + + if(current_fit > prev_fit) { // fit is worse than previously + proceed = Proceed::LOWER; + } else { // good to go, create the triangle + inverted? rfaces.emplace_back(unextidx, lidx, uidx) : + rfaces.emplace_back(uidx, lidx, unextidx) ; + + // Increment the iterators, rotate if necessary + ++uidx; ++unextidx; + if(unextidx == offs) unextidx = 0; + if(uidx == offs) uidx = 0; + + ustarted = true; // mark the movement of the iterators + // so that the comparison to uendidx can be made correctly + } + } else proceed = Proceed::LOWER; + + break; + case Proceed::LOWER: + // Mode with lower segment, upper vertex. Same structure: + if(!lstarted || lidx != lendidx) { + const Vec3d& p_low1 = rpts[size_t(lidx)]; + const Vec3d& p_low2 = rpts[size_t(lnextidx)]; + const Vec3d& p_up = rpts[size_t(uidx)]; + + double a = offsdiff2 - (distfn(p_up, p_low1) - zdiff2); + double b = offsdiff2 - (distfn(p_up, p_low2) - zdiff2); + current_fit = (std::abs(a) + std::abs(b)) / 2; + + if(current_fit > prev_fit) { + proceed = Proceed::UPPER; + } else { + inverted? rfaces.emplace_back(uidx, lnextidx, lidx) : + rfaces.emplace_back(lidx, lnextidx, uidx); + + ++lidx; ++lnextidx; + if(lnextidx == rpts.size()) lnextidx = offs; + if(lidx == rpts.size()) lidx = offs; + + lstarted = true; + } + } else proceed = Proceed::UPPER; + + break; + } // end of switch + } while(!ustarted || !lstarted || uidx != uendidx || lidx != lendidx); return ret; } @@ -207,20 +306,31 @@ ExPolygons unify(const ExPolygons& shapes) { /// Only a debug function to generate top and bottom plates from a 2D shape. /// It is not used in the algorithm directly. inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) { - Polygons triangles = triangulate(poly); - - auto lower = convert(triangles, 0, false); - auto upper = convert(triangles, z_distance, true); - lower.merge(upper); - return lower; + auto lower = triangulate_expolygon_3d(poly); + auto upper = triangulate_expolygon_3d(poly, z_distance*SCALING_FACTOR, true); + Contour3D ret; + ret.merge(lower); ret.merge(upper); + return ret; } +/// This method will create a rounded edge around a flat polygon in 3d space. +/// 'base_plate' parameter is the target plate. +/// 'radius' is the radius of the edges. +/// 'degrees' is tells how much of a circle should be created as the rounding. +/// It should be in degrees, not radians. +/// 'ceilheight_mm' is the Z coordinate of the flat polygon in 3D space. +/// 'dir' Is the direction of the round edges: inward or outward +/// 'thr' Throws if a cancel signal was received +/// 'last_offset' An auxiliary output variable to save the last offsetted +/// version of 'base_plate' +/// 'last_height' An auxiliary output to save the last z coordinate of the +/// offsetted base_plate. In other words, where the rounded edges end. Contour3D round_edges(const ExPolygon& base_plate, double radius_mm, double degrees, double ceilheight_mm, bool dir, - ThrowOnCancel throw_on_cancel, + ThrowOnCancel thr, ExPolygon& last_offset, double& last_height) { auto ob = base_plate; @@ -236,10 +346,10 @@ Contour3D round_edges(const ExPolygon& base_plate, // we use sin for x distance because we interpret the angle starting from // PI/2 int tos = degrees < 90? - int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps; + int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps; for(int i = 1; i <= tos; ++i) { - throw_on_cancel(); + thr(); ob = base_plate; @@ -252,7 +362,8 @@ Contour3D round_edges(const ExPolygon& base_plate, wh = ceilheight_mm - radius_mm + stepy; Contour3D pwalls; - pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel); + double prev_x = xx - (i - 1) * stepx; + pwalls = walls(ob.contour, ob_prev.contour, wh, wh_prev, s*prev_x, thr); curvedwalls.merge(pwalls); ob_prev = ob; @@ -264,7 +375,7 @@ Contour3D round_edges(const ExPolygon& base_plate, int tos = int(tox / stepx); for(int i = 1; i <= tos; ++i) { - throw_on_cancel(); + thr(); ob = base_plate; double r2 = radius_mm * radius_mm; @@ -275,7 +386,9 @@ Contour3D round_edges(const ExPolygon& base_plate, wh = ceilheight_mm - radius_mm - stepy; Contour3D pwalls; - pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel); + double prev_x = xx - radius_mm + (i - 1)*stepx; + pwalls = + walls(ob_prev.contour, ob.contour, wh_prev, wh, s*prev_x, thr); curvedwalls.merge(pwalls); ob_prev = ob; @@ -291,15 +404,17 @@ Contour3D round_edges(const ExPolygon& base_plate, /// Generating the concave part of the 3D pool with the bottom plate and the /// side walls. -Contour3D inner_bed(const ExPolygon& poly, double depth_mm, - double begin_h_mm = 0) { - - Polygons triangles = triangulate(poly); +Contour3D inner_bed(const ExPolygon& poly, + double depth_mm, + double begin_h_mm = 0) +{ + Contour3D bottom; + Pointf3s triangles = triangulate_expolygon_3d(poly, -depth_mm + begin_h_mm); + bottom.merge(triangles); coord_t depth = mm(depth_mm); coord_t begin_h = mm(begin_h_mm); - auto bottom = convert(triangles, -depth + begin_h, false); auto lines = poly.lines(); // Generate outer walls @@ -446,7 +561,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, heights.emplace_back(hi); std::vector out; out.reserve(size_t(std::ceil(h/layerh))); - slicer.slice(heights, &out, thrfn); + slicer.slice(heights, 0.f, &out, thrfn); size_t count = 0; for(auto& o : out) count += o.size(); @@ -469,6 +584,9 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, const PoolConfig& cfg) { + // for debugging: + // Benchmark bench; + // bench.start(); double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+ cfg.max_merge_distance_mm; @@ -478,27 +596,28 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // serve as the bottom plate of the pad. We will offset this concave hull // and then offset back the result with clipper with rounding edges ON. This // trick will create a nice rounded pad shape. - auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); + ExPolygons concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); const double thickness = cfg.min_wall_thickness_mm; const double wingheight = cfg.min_wall_height_mm; const double fullheight = wingheight + thickness; - const double tilt = PI/4; - const double wingdist = wingheight / std::tan(tilt); + const double slope = cfg.wall_slope; + const double wingdist = wingheight / std::tan(slope); // scaled values const coord_t s_thickness = mm(thickness); const coord_t s_eradius = mm(cfg.edge_radius_mm); const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness); - // const coord_t wheight = mm(cfg.min_wall_height_mm); - coord_t s_wingdist = mm(wingdist); + const coord_t s_wingdist = mm(wingdist); auto& thrcl = cfg.throw_on_cancel; + Contour3D pool; + for(ExPolygon& concaveh : concavehs) { if(concaveh.contour.points.empty()) return; - // Get rif of any holes in the concave hull output. + // Get rid of any holes in the concave hull output. concaveh.holes.clear(); // Here lies the trick that does the smooting only with clipper offset @@ -508,15 +627,22 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, auto outer_base = concaveh; outer_base.holes.clear(); offset(outer_base, s_safety_dist + s_wingdist + s_thickness); - auto inner_base = outer_base; - offset(inner_base, -(s_thickness + s_wingdist)); + + + ExPolygon bottom_poly = outer_base; + bottom_poly.holes.clear(); + if(s_wingdist > 0) offset(bottom_poly, -s_wingdist); // Punching a hole in the top plate for the cavity ExPolygon top_poly; ExPolygon middle_base; + ExPolygon inner_base; top_poly.contour = outer_base.contour; if(wingheight > 0) { + inner_base = outer_base; + offset(inner_base, -(s_thickness + s_wingdist + s_eradius)); + middle_base = outer_base; offset(middle_base, -s_thickness); top_poly.holes.emplace_back(middle_base.contour); @@ -524,8 +650,6 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, std::reverse(tph.begin(), tph.end()); } - Contour3D pool; - ExPolygon ob = outer_base; double wh = 0; // now we will calculate the angle or portion of the circle from @@ -557,60 +681,53 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // Generate the smoothed edge geometry - auto walledges = round_edges(ob, - r, - phi, - 0, // z position of the input plane - true, - thrcl, - ob, wh); - pool.merge(walledges); + pool.merge(round_edges(ob, + r, + phi, + 0, // z position of the input plane + true, + thrcl, + ob, wh)); - // Now that we have the rounded edge connencting the top plate with + // Now that we have the rounded edge connecting the top plate with // the outer side walls, we can generate and merge the sidewall geometry - auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl); - pool.merge(pwalls); + pool.merge(walls(ob.contour, bottom_poly.contour, wh, -fullheight, + wingdist, thrcl)); if(wingheight > 0) { // Generate the smoothed edge geometry - auto cavityedges = round_edges(middle_base, - r, - phi - 90, // from tangent lines - 0, - false, - thrcl, - ob, wh); - pool.merge(cavityedges); + pool.merge(round_edges(middle_base, + r, + phi - 90, // from tangent lines + 0, // z position of the input plane + false, + thrcl, + ob, wh)); // Next is the cavity walls connecting to the top plate's // artificially created hole. - auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl); - pool.merge(cavitywalls); + pool.merge(walls(inner_base.contour, ob.contour, -wingheight, + wh, -wingdist, thrcl)); } // Now we need to triangulate the top and bottom plates as well as the // cavity bottom plate which is the same as the bottom plate but it is - // eleveted by the thickness. - Polygons top_triangles, bottom_triangles; + // elevated by the thickness. + pool.merge(triangulate_expolygon_3d(top_poly)); + pool.merge(triangulate_expolygon_3d(bottom_poly, -fullheight, true)); - triangulate(top_poly, top_triangles); - triangulate(inner_base, bottom_triangles); + if(wingheight > 0) + pool.merge(triangulate_expolygon_3d(inner_base, -wingheight)); - auto top_plate = convert(top_triangles, 0, false); - auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true); - - pool.merge(top_plate); - pool.merge(bottom_plate); - - if(wingheight > 0) { - Polygons middle_triangles; - triangulate(inner_base, middle_triangles); - auto middle_plate = convert(middle_triangles, -mm(wingheight), false); - pool.merge(middle_plate); - } - - out.merge(mesh(pool)); } + + // For debugging: + // bench.stop(); + // std::cout << "Pad creation time: " << bench.getElapsedSec() << std::endl; + // std::fstream fout("pad_debug.obj", std::fstream::out); + // if(fout.good()) pool.to_obj(fout); + + out.merge(mesh(pool)); } } diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp index 3917d995b..3c88e58c8 100644 --- a/src/libslic3r/SLA/SLABasePool.hpp +++ b/src/libslic3r/SLA/SLABasePool.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Slic3r { @@ -27,15 +28,17 @@ struct PoolConfig { double min_wall_height_mm = 5; double max_merge_distance_mm = 50; double edge_radius_mm = 1; + double wall_slope = std::atan(1.0); // Universal constant for Pi/4 ThrowOnCancel throw_on_cancel = [](){}; inline PoolConfig() {} - inline PoolConfig(double wt, double wh, double md, double er): + inline PoolConfig(double wt, double wh, double md, double er, double slope): min_wall_thickness_mm(wt), min_wall_height_mm(wh), max_merge_distance_mm(md), - edge_radius_mm(er) {} + edge_radius_mm(er), + wall_slope(slope) {} }; /// Calculate the pool for the mesh for SLA printing diff --git a/src/libslic3r/SLA/SLABoilerPlate.hpp b/src/libslic3r/SLA/SLABoilerPlate.hpp index c1096206a..602121af9 100644 --- a/src/libslic3r/SLA/SLABoilerPlate.hpp +++ b/src/libslic3r/SLA/SLABoilerPlate.hpp @@ -36,14 +36,6 @@ inline coord_t x(const Vec3crd& p) { return p(0); } inline coord_t y(const Vec3crd& p) { return p(1); } inline coord_t z(const Vec3crd& p) { return p(2); } -inline void triangulate(const ExPolygon& expoly, Polygons& triangles) { - expoly.triangulate_p2t(&triangles); -} - -inline Polygons triangulate(const ExPolygon& expoly) { - Polygons tri; triangulate(expoly, tri); return tri; -} - using Indices = std::vector; /// Intermediate struct for a 3D mesh @@ -63,6 +55,15 @@ struct Contour3D { } } + void merge(const Pointf3s& triangles) { + const size_t offs = points.size(); + points.insert(points.end(), triangles.begin(), triangles.end()); + indices.reserve(indices.size() + points.size() / 3); + + for(int i = (int)offs; i < (int)points.size(); i += 3) + indices.emplace_back(i, i + 1, i + 2); + } + // Write the index triangle structure to OBJ file for debugging purposes. void to_obj(std::ostream& stream) { for(auto& p : points) { @@ -75,13 +76,9 @@ struct Contour3D { } }; -//using PointSet = Eigen::Matrix; //Eigen::MatrixXd; using ClusterEl = std::vector; using ClusteredPoints = std::vector; -/// Convert the triangulation output to an intermediate mesh. -Contour3D convert(const Polygons& triangles, coord_t z, bool dir); - /// Mesh from an existing contour. inline TriangleMesh mesh(const Contour3D& ctour) { return {ctour.points, ctour.indices}; diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp new file mode 100644 index 000000000..bdeead9ca --- /dev/null +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -0,0 +1,145 @@ +#ifndef SLACOMMON_HPP +#define SLACOMMON_HPP + +#include + +// #define SLIC3R_SLA_NEEDS_WINDTREE + +namespace Slic3r { + +// Typedefs from Point.hpp +typedef Eigen::Matrix Vec3f; +typedef Eigen::Matrix Vec3d; + +class TriangleMesh; + +namespace sla { + +// An enum to keep track of where the current points on the ModelObject came from. +enum class PointsStatus { + None, // No points were generated so far. + Generating, // The autogeneration algorithm triggered, but not yet finished. + AutoGenerated, // Points were autogenerated (i.e. copied from the backend). + UserModified // User has done some edits. +}; + +struct SupportPoint { + Vec3f pos; + float head_front_radius; + bool is_new_island; + + SupportPoint() : + pos(Vec3f::Zero()), head_front_radius(0.f), is_new_island(false) {} + + SupportPoint(float pos_x, float pos_y, float pos_z, float head_radius, bool new_island) : + pos(pos_x, pos_y, pos_z), head_front_radius(head_radius), is_new_island(new_island) {} + + SupportPoint(Vec3f position, float head_radius, bool new_island) : + pos(position), head_front_radius(head_radius), is_new_island(new_island) {} + + SupportPoint(Eigen::Matrix data) : + pos(data(0), data(1), data(2)), head_front_radius(data(3)), is_new_island(data(4) != 0.f) {} + + bool operator==(const SupportPoint& sp) const { return (pos==sp.pos) && head_front_radius==sp.head_front_radius && is_new_island==sp.is_new_island; } + bool operator!=(const SupportPoint& sp) const { return !(sp == (*this)); } +}; + + +/// An index-triangle structure for libIGL functions. Also serves as an +/// alternative (raw) input format for the SLASupportTree +/*struct EigenMesh3D { + Eigen::MatrixXd V; + Eigen::MatrixXi F; + double ground_level = 0; +};*/ + +/// An index-triangle structure for libIGL functions. Also serves as an +/// alternative (raw) input format for the SLASupportTree +class EigenMesh3D { + class AABBImpl; + + Eigen::MatrixXd m_V; + Eigen::MatrixXi m_F; + double m_ground_level = 0; + + std::unique_ptr m_aabb; +public: + + EigenMesh3D(const TriangleMesh&); + EigenMesh3D(const EigenMesh3D& other); + EigenMesh3D& operator=(const EigenMesh3D&); + + ~EigenMesh3D(); + + inline double ground_level() const { return m_ground_level; } + + inline const Eigen::MatrixXd& V() const { return m_V; } + inline const Eigen::MatrixXi& F() const { return m_F; } + + // Result of a raycast + class hit_result { + double m_t = std::numeric_limits::infinity(); + int m_face_id = -1; + const EigenMesh3D& m_mesh; + Vec3d m_dir; + inline hit_result(const EigenMesh3D& em): m_mesh(em) {} + friend class EigenMesh3D; + public: + + inline double distance() const { return m_t; } + inline const Vec3d& direction() const { return m_dir; } + inline int face() const { return m_face_id; } + + inline Vec3d normal() const { + if(m_face_id < 0) return {}; + auto trindex = m_mesh.m_F.row(m_face_id); + const Vec3d& p1 = m_mesh.V().row(trindex(0)); + const Vec3d& p2 = m_mesh.V().row(trindex(1)); + const Vec3d& p3 = m_mesh.V().row(trindex(2)); + Eigen::Vector3d U = p2 - p1; + Eigen::Vector3d V = p3 - p1; + return U.cross(V).normalized(); + } + + inline bool is_inside() { + return m_face_id >= 0 && normal().dot(m_dir) > 0; + } + }; + + // Casting a ray on the mesh, returns the distance where the hit occures. + hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const; + + class si_result { + double m_value; + int m_fidx; + Vec3d m_p; + si_result(double val, int i, const Vec3d& c): + m_value(val), m_fidx(i), m_p(c) {} + friend class EigenMesh3D; + public: + + si_result() = delete; + + double value() const { return m_value; } + operator double() const { return m_value; } + const Vec3d& point_on_mesh() const { return m_p; } + int F_idx() const { return m_fidx; } + }; + +#ifdef SLIC3R_SLA_NEEDS_WINDTREE + // The signed distance from a point to the mesh. Outputs the distance, + // the index of the triangle and the closest point in mesh coordinate space. + si_result signed_distance(const Vec3d& p) const; + + bool inside(const Vec3d& p) const; +#endif /* SLIC3R_SLA_NEEDS_WINDTREE */ +}; + + + + +} // namespace sla +} // namespace Slic3r + + +#endif // SLASUPPORTTREE_HPP \ No newline at end of file diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 5a5187093..0ba09ead8 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -550,10 +551,16 @@ enum { // For indexing Eigen vectors as v(X), v(Y), v(Z) instead of numbers X, Y, Z }; -PointSet to_point_set(const std::vector &v) +PointSet to_point_set(const std::vector &v) { PointSet ret(v.size(), 3); - { long i = 0; for(const Vec3d& p : v) ret.row(i++) = p; } + long i = 0; + for(const SupportPoint& support_point : v) { + ret.row(i)(0) = support_point.pos(0); + ret.row(i)(1) = support_point.pos(1); + ret.row(i)(2) = support_point.pos(2); + ++i; + } return ret; } @@ -588,7 +595,7 @@ double pinhead_mesh_intersect(const Vec3d& s, double r_back, double width, const EigenMesh3D& m, - unsigned samples = 8, + unsigned samples = 16, double safety_distance = 0.001) { // method based on: @@ -614,9 +621,20 @@ double pinhead_mesh_intersect(const Vec3d& s, std::vector phis(samples); for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size(); - a(Z) = -(v(X)*a(X) + v(Y)*a(Y)) / v(Z); - - b = a.cross(v); + // We have to address the case when the direction vector v (same as dir) + // is coincident with one of the world axes. In this case two of its + // components will be completely zero and one is 1.0. Our method becomes + // dangerous here due to division with zero. Instead, vector 'a' can be an + // element-wise rotated version of 'v' + auto chk1 = [] (double val) { return std::abs(std::abs(val) - 1) < 1e-20; }; + if(chk1(v(X)) || chk1(v(Y)) || chk1(v(Z))) { + a = {v(Z), v(X), v(Y)}; + b = {v(Y), v(Z), v(X)}; + } + else { + a(Z) = -(v(Y)*a(Y)) / v(Z); a.normalize(); + b = a.cross(v); + } // Now a and b vectors are perpendicular to v and to each other. Together // they define the plane where we have to iterate with the given angles @@ -641,18 +659,14 @@ double pinhead_mesh_intersect(const Vec3d& s, s(Z) + rpscos * a(Z) + rpssin * b(Z)); // Point ps is not on mesh but can be inside or outside as well. This - // would cause many problems with ray-casting. So we query the closest - // point on the mesh to this. -// auto psq = m.signed_distance(ps); + // would cause many problems with ray-casting. To detect the position we + // will use the ray-casting result (which has an is_inside predicate). // This is the point on the circle on the back sphere Vec3d p(c(X) + rpbcos * a(X) + rpbsin * b(X), c(Y) + rpbcos * a(Y) + rpbsin * b(Y), c(Z) + rpbcos * a(Z) + rpbsin * b(Z)); -// Vec3d n = (p - psq.point_on_mesh()).normalized(); -// phi = m.query_ray_hit(psq.point_on_mesh() + sd*n, n); - Vec3d n = (p - ps).normalized(); auto hr = m.query_ray_hit(ps + sd*n, n); @@ -671,6 +685,7 @@ double pinhead_mesh_intersect(const Vec3d& s, return *mit; } + // Checking bridge (pillar and stick as well) intersection with the model. If // the function is used for headless sticks, the ins_check parameter have to be // true as the beginning of the stick might be inside the model geometry. @@ -686,8 +701,18 @@ double bridge_mesh_intersect(const Vec3d& s, Vec3d a(0, 1, 0), b; const double& sd = safety_distance; - a(Z) = -(dir(X)*a(X) + dir(Y)*a(Y)) / dir(Z); - b = a.cross(dir); + // INFO: for explanation of the method used here, see the previous method's + // comments. + + auto chk1 = [] (double val) { return std::abs(std::abs(val) - 1) < 1e-20; }; + if(chk1(dir(X)) || chk1(dir(Y)) || chk1(dir(Z))) { + a = {dir(Z), dir(X), dir(Y)}; + b = {dir(Y), dir(Z), dir(X)}; + } + else { + a(Z) = -(dir(Y)*a(Y)) / dir(Z); a.normalize(); + b = a.cross(dir); + } // circle portions std::vector phis(samples); @@ -1149,16 +1174,16 @@ bool SLASupportTree::generate(const PointSet &points, //... }; - // t-hrow i-f c-ance-l-ed: It will be called many times so a shorthand will + // throw if canceled: It will be called many times so a shorthand will // come in handy. - auto& tifcl = ctl.cancelfn; + auto& thr = ctl.cancelfn; // Filtering step: here we will discard inappropriate support points and // decide the future of the appropriate ones. We will check if a pinhead // is applicable and adjust its angle at each support point. // We will also merge the support points that are just too close and can be // considered as one. - auto filterfn = [tifcl] ( + auto filterfn = [thr] ( const SupportConfig& cfg, const PointSet& points, const EigenMesh3D& mesh, @@ -1172,9 +1197,9 @@ bool SLASupportTree::generate(const PointSet &points, // first one auto aliases = cluster(points, - [tifcl](const SpatElement& p, const SpatElement& se) + [thr](const SpatElement& p, const SpatElement& se) { - tifcl(); + thr(); return distance(p.first, se.first) < D_SP; }, 2); @@ -1185,10 +1210,10 @@ bool SLASupportTree::generate(const PointSet &points, filt_pts.row(count++) = points.row(a.front()); } - tifcl(); + thr(); // calculate the normals to the triangles belonging to filtered points - auto nmls = sla::normals(filt_pts, mesh, cfg.head_front_radius_mm, tifcl); + auto nmls = sla::normals(filt_pts, mesh, cfg.head_front_radius_mm, thr); head_norm.resize(count, 3); head_pos.resize(count, 3); @@ -1200,9 +1225,15 @@ bool SLASupportTree::generate(const PointSet &points, // not be enough space for the pinhead. Filtering is applied for // these reasons. + using libnest2d::opt::bound; + using libnest2d::opt::initvals; + using libnest2d::opt::SimplexOptimizer; + using libnest2d::opt::StopCriteria; + static const unsigned MAX_TRIES = 100; + int pcount = 0, hlcount = 0; for(int i = 0; i < count; i++) { - tifcl(); + thr(); auto n = nmls.row(i); // for all normals we generate the spherical coordinates and @@ -1223,32 +1254,67 @@ bool SLASupportTree::generate(const PointSet &points, // We saturate the polar angle to 3pi/4 polar = std::max(polar, 3*PI / 4); - // Reassemble the now corrected normal - Vec3d nn(std::cos(azimuth) * std::sin(polar), - std::sin(azimuth) * std::sin(polar), - std::cos(polar)); - - nn.normalize(); - // save the head (pinpoint) position Vec3d hp = filt_pts.row(i); - // the full width of the head double w = cfg.head_width_mm + cfg.head_back_radius_mm + 2*cfg.head_front_radius_mm; - // We should shoot a ray in the direction of the pinhead and - // see if there is enough space for it - double t = pinhead_mesh_intersect( - hp, // touching point - nn, - cfg.head_front_radius_mm, // approx the radius - cfg.head_back_radius_mm, - w, - mesh); + // Reassemble the now corrected normal + auto nn = Vec3d(std::cos(azimuth) * std::sin(polar), + std::sin(azimuth) * std::sin(polar), + std::cos(polar)).normalized(); - if(t > w || std::isinf(t)) { + // check available distance + double t = pinhead_mesh_intersect( + hp, // touching point + nn, // normal + cfg.head_front_radius_mm, + cfg.head_back_radius_mm, + w, + mesh); + + if(t <= w) { + // Let's try to optimize this angle, there might be a viable + // normal that doesn't collide with the model geometry and + // its very close to the default. + + StopCriteria stc; + stc.max_iterations = MAX_TRIES; + stc.relative_score_difference = 1e-3; + stc.stop_score = w; // space greater than w is enough + SimplexOptimizer solver(stc); + + auto oresult = solver.optimize_max( + [&mesh, &cfg, w, hp](double plr, double azm) + { + auto n = Vec3d(std::cos(azm) * std::sin(plr), + std::sin(azm) * std::sin(plr), + std::cos(plr)).normalized(); + + double score = pinhead_mesh_intersect( + hp, n, + cfg.head_front_radius_mm, + cfg.head_back_radius_mm, + w, + mesh); + return score; + }, + initvals(polar, azimuth), // let's start with what we have + bound(3*PI/4, PI), // Must not exceed the tilt limit + bound(-PI, PI) // azimuth can be a full range search + ); + + t = oresult.score; + polar = std::get<0>(oresult.optimum); + azimuth = std::get<1>(oresult.optimum); + nn = Vec3d(std::cos(azimuth) * std::sin(polar), + std::sin(azimuth) * std::sin(polar), + std::cos(polar)).normalized(); + } + + if(t > w) { head_pos.row(pcount) = hp; // save the verified and corrected normal @@ -1256,6 +1322,7 @@ bool SLASupportTree::generate(const PointSet &points, ++pcount; } else if( polar >= 3*PI/4 ) { + // Headless supports do not tilt like the headed ones so // the normal should point almost to the ground. headless_norm.row(hlcount) = nn; @@ -1272,7 +1339,7 @@ bool SLASupportTree::generate(const PointSet &points, // Pinhead creation: based on the filtering results, the Head objects will // be constructed (together with their triangle meshes). - auto pinheadfn = [tifcl] ( + auto pinheadfn = [thr] ( const SupportConfig& cfg, PointSet& head_pos, PointSet& nmls, @@ -1285,7 +1352,7 @@ bool SLASupportTree::generate(const PointSet &points, /* ******************************************************** */ for (int i = 0; i < head_pos.rows(); ++i) { - tifcl(); + thr(); result.add_head( cfg.head_back_radius_mm, cfg.head_front_radius_mm, @@ -1304,7 +1371,7 @@ bool SLASupportTree::generate(const PointSet &points, // will process it. Also, the pillars will be grouped into clusters that can // be interconnected with bridges. Elements of these groups may or may not // be interconnected. Here we only run the clustering algorithm. - auto classifyfn = [tifcl] ( + auto classifyfn = [thr] ( const SupportConfig& cfg, const EigenMesh3D& mesh, PointSet& head_pos, @@ -1313,7 +1380,8 @@ bool SLASupportTree::generate(const PointSet &points, std::vector& gndheight, ClusteredPoints& ground_clusters, Result& result - ) { + ) + { /* ******************************************************** */ /* Classification */ @@ -1324,11 +1392,11 @@ bool SLASupportTree::generate(const PointSet &points, gndidx.reserve(size_t(head_pos.rows())); nogndidx.reserve(size_t(head_pos.rows())); - // First we search decide which heads reach the ground and can be full + // First we decide which heads reach the ground and can be full // pillars and which shall be connected to the model surface (or search // a suitable path around the surface that leads to the ground -- TODO) for(unsigned i = 0; i < head_pos.rows(); i++) { - tifcl(); + thr(); auto& head = result.head(i); Vec3d dir(0, 0, -1); @@ -1337,9 +1405,38 @@ bool SLASupportTree::generate(const PointSet &points, double t = std::numeric_limits::infinity(); double hw = head.width_mm; + + { +// using libnest2d::opt::Method; +// using libnest2d::opt::bound; +// using libnest2d::opt::Optimizer; +// using libnest2d::opt::TOptimizer; +// using libnest2d::opt::StopCriteria; + +// auto stopcond = [] () { return false; }; +// static const unsigned max_tries = 100; + +// auto objfunc = +// [&head](double polar, double azimuth, double width) +// { +// Vec3d nn(std::cos(azimuth) * std::sin(polar), +// std::sin(azimuth) * std::sin(polar), +// std::cos(polar)); + + +// }; + +// StopCriteria stc; +// stc.max_iterations = max_tries; +// stc.relative_score_difference = 1e-3; +// stc.stop_condition = stopcond; +// TOptimizer solver(stc); + } + + // We will try to assign a pillar to all the pinheads. If a pillar // would pierce the model surface, we will try to adjust slightly - // the head with so that the pillar can be deployed. + // the head width so that the pillar can be deployed. while(!accept && head.width_mm > 0) { Vec3d startpoint = head.junction_point(); @@ -1351,11 +1448,18 @@ bool SLASupportTree::generate(const PointSet &points, double tprec = ray_mesh_intersect(startpoint, dir, mesh); if(std::isinf(tprec) && !std::isinf(t)) { - // This is a damned case where the pillar melds into the + // This is a damned case where the pillar melts into the // model but its center ray can reach the ground. We can // not route this to the ground nor to the model surface. head.width_mm = hw + (ri % 2? -1 : 1) * ri * head.r_back_mm; } else { + if(!std::isinf(t) && !std::isinf(tprec) && + std::abs(tprec - t) > hw) + { + // In this case the head would scratch the model body + BOOST_LOG_TRIVIAL(warning) << "Head scratch detected."; + } + accept = true; t = tprec; auto id = head.id; @@ -1410,9 +1514,9 @@ bool SLASupportTree::generate(const PointSet &points, ground_clusters = cluster( gnd, - [d_base, tifcl](const SpatElement& p, const SpatElement& s) + [d_base, thr](const SpatElement& p, const SpatElement& s) { - tifcl(); + thr(); return distance(Vec2d(p.first(X), p.first(Y)), Vec2d(s.first(X), s.first(Y))) < d_base; }, 3); // max 3 heads to connect to one centroid @@ -1485,7 +1589,7 @@ bool SLASupportTree::generate(const PointSet &points, // a full pillar (ground connected). Some will connect to a nearby pillar // using a bridge. The max number of such side-heads for a central pillar // is limited to avoid bad weight distribution. - auto routing_ground_fn = [gnd_head_pt, interconnect, tifcl]( + auto routing_ground_fn = [gnd_head_pt, interconnect, thr]( const SupportConfig& cfg, const ClusteredPoints& gnd_clusters, const IndexSet& gndidx, @@ -1501,7 +1605,7 @@ bool SLASupportTree::generate(const PointSet &points, cl_centroids.reserve(gnd_clusters.size()); SpatIndex pheadindex; // spatial index for the junctions - for(auto& cl : gnd_clusters) { tifcl(); + for(auto& cl : gnd_clusters) { thr(); // place all the centroid head positions into the index. We will // query for alternative pillar positions. If a sidehead cannot // connect to the cluster centroid, we have to search for another @@ -1512,9 +1616,9 @@ bool SLASupportTree::generate(const PointSet &points, // get the current cluster centroid long lcid = cluster_centroid(cl, gnd_head_pt, - [tifcl](const Vec3d& p1, const Vec3d& p2) + [thr](const Vec3d& p1, const Vec3d& p2) { - tifcl(); + thr(); return distance(Vec2d(p1(X), p1(Y)), Vec2d(p2(X), p2(Y))); }); @@ -1535,7 +1639,7 @@ bool SLASupportTree::generate(const PointSet &points, // sidepoints with the cluster centroid (which is a ground pillar) // or a nearby pillar if the centroid is unreachable. size_t ci = 0; - for(auto cl : gnd_clusters) { tifcl(); + for(auto cl : gnd_clusters) { thr(); auto cidx = cl_centroids[ci]; cl_centroids[ci++] = cl[cidx]; @@ -1559,12 +1663,12 @@ bool SLASupportTree::generate(const PointSet &points, // is distributed more effectively on the pillar. auto search_nearest = - [&tifcl, &cfg, &result, &emesh, maxbridgelen, gndlvl, pradius] + [&thr, &cfg, &result, &emesh, maxbridgelen, gndlvl, pradius] (SpatIndex& spindex, const Vec3d& jsh) { long nearest_id = -1; const double max_len = maxbridgelen / 2; - while(nearest_id < 0 && !spindex.empty()) { tifcl(); + while(nearest_id < 0 && !spindex.empty()) { thr(); // loop until a suitable head is not found // if there is a pillar closer than the cluster center // (this may happen as the clustering is not perfect) @@ -1603,7 +1707,7 @@ bool SLASupportTree::generate(const PointSet &points, return nearest_id; }; - for(auto c : cl) { tifcl(); + for(auto c : cl) { thr(); auto& sidehead = result.head(gndidx[c]); sidehead.transform(); @@ -1669,7 +1773,7 @@ bool SLASupportTree::generate(const PointSet &points, ClusterEl ring; while(!rem.empty()) { // loop until all the points belong to some ring - tifcl(); + thr(); std::sort(rem.begin(), rem.end()); auto newring = pts_convex_hull(rem, @@ -1681,7 +1785,7 @@ bool SLASupportTree::generate(const PointSet &points, if(!ring.empty()) { // inner ring is now in 'newring' and outer ring is in 'ring' SpatIndex innerring; - for(unsigned i : newring) { tifcl(); + for(unsigned i : newring) { thr(); const Pillar& pill = result.head_pillar(gndidx[i]); assert(pill.id >= 0); innerring.insert(pill.endpoint, unsigned(pill.id)); @@ -1690,7 +1794,7 @@ bool SLASupportTree::generate(const PointSet &points, // For all pillars in the outer ring find the closest in the // inner ring and connect them. This will create the spider web // fashioned connections between pillars - for(unsigned i : ring) { tifcl(); + for(unsigned i : ring) { thr(); const Pillar& outerpill = result.head_pillar(gndidx[i]); auto res = innerring.nearest(outerpill.endpoint, 1); if(res.empty()) continue; @@ -1716,7 +1820,7 @@ bool SLASupportTree::generate(const PointSet &points, next != ring.end(); ++it, ++next) { - tifcl(); + thr(); const Pillar& pillar = result.head_pillar(gndidx[*it]); const Pillar& nextpillar = result.head_pillar(gndidx[*next]); interconnect(pillar, nextpillar, emesh, result); @@ -1731,19 +1835,19 @@ bool SLASupportTree::generate(const PointSet &points, } }; - // Step: routing the pinheads that are would connect to the model surface + // Step: routing the pinheads that would connect to the model surface // along the Z axis downwards. For now these will actually be connected with // the model surface with a flipped pinhead. In the future here we could use // some smart algorithms to search for a safe path to the ground or to a // nearby pillar that can hold the supported weight. - auto routing_nongnd_fn = [tifcl]( + auto routing_nongnd_fn = [thr]( const SupportConfig& cfg, const std::vector& gndheight, const IndexSet& nogndidx, Result& result) { // TODO: connect these to the ground pillars if possible - for(auto idx : nogndidx) { tifcl(); + for(auto idx : nogndidx) { thr(); double gh = gndheight[idx]; double base_width = cfg.head_width_mm; @@ -1800,7 +1904,7 @@ bool SLASupportTree::generate(const PointSet &points, // Step: process the support points where there is not enough space for a // full pinhead. In this case we will use a rounded sphere as a touching // point and use a thinner bridge (let's call it a stick). - auto process_headless = [tifcl]( + auto process_headless = [thr]( const SupportConfig& cfg, const PointSet& headless_pts, const PointSet& headless_norm, @@ -1815,7 +1919,7 @@ bool SLASupportTree::generate(const PointSet &points, // We will sink the pins into the model surface for a distance of 1/3 of // the pin radius - for(int i = 0; i < headless_pts.rows(); i++) { tifcl(); + for(int i = 0; i < headless_pts.rows(); i++) { thr(); Vec3d sph = headless_pts.row(i); // Exact support position Vec3d n = headless_norm.row(i); // mesh outward normal Vec3d sp = sph - n * HWIDTH_MM; // stick head start point @@ -2001,7 +2105,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const fullmesh.merge(get_pad()); TriangleMeshSlicer slicer(&fullmesh); SlicedSupports ret; - slicer.slice(heights, &ret, get().ctl().cancelfn); + slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn); return ret; } diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index 7d23a981f..c29b2a571 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -7,6 +7,9 @@ #include #include +#include "SLACommon.hpp" + + namespace Slic3r { // Needed types from Point.hpp @@ -105,86 +108,6 @@ struct Controller { std::function cancelfn = [](){}; }; -/// An index-triangle structure for libIGL functions. Also serves as an -/// alternative (raw) input format for the SLASupportTree -class EigenMesh3D { - class AABBImpl; - - Eigen::MatrixXd m_V; - Eigen::MatrixXi m_F; - double m_ground_level = 0; - - std::unique_ptr m_aabb; -public: - - EigenMesh3D(const TriangleMesh&); - EigenMesh3D(const EigenMesh3D& other); - EigenMesh3D& operator=(const EigenMesh3D&); - - ~EigenMesh3D(); - - inline double ground_level() const { return m_ground_level; } - - inline const Eigen::MatrixXd& V() const { return m_V; } - inline const Eigen::MatrixXi& F() const { return m_F; } - - // Result of a raycast - class hit_result { - double m_t = std::numeric_limits::infinity(); - int m_face_id = -1; - const EigenMesh3D& m_mesh; - Vec3d m_dir; - inline hit_result(const EigenMesh3D& em): m_mesh(em) {} - friend class EigenMesh3D; - public: - - inline double distance() const { return m_t; } - - inline int face() const { return m_face_id; } - - inline Vec3d normal() const { - if(m_face_id < 0) return {}; - auto trindex = m_mesh.m_F.row(m_face_id); - const Vec3d& p1 = m_mesh.V().row(trindex(0)); - const Vec3d& p2 = m_mesh.V().row(trindex(1)); - const Vec3d& p3 = m_mesh.V().row(trindex(2)); - Eigen::Vector3d U = p2 - p1; - Eigen::Vector3d V = p3 - p1; - return U.cross(V).normalized(); - } - - inline bool is_inside() { - return m_face_id >= 0 && normal().dot(m_dir) > 0; - } - }; - - // Casting a ray on the mesh, returns the distance where the hit occures. - hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const; - - class si_result { - double m_value; - int m_fidx; - Vec3d m_p; - si_result(double val, int i, const Vec3d& c): - m_value(val), m_fidx(i), m_p(c) {} - friend class EigenMesh3D; - public: - - si_result() = delete; - - double value() const { return m_value; } - operator double() const { return m_value; } - const Vec3d& point_on_mesh() const { return m_p; } - int F_idx() const { return m_fidx; } - }; - - // The signed distance from a point to the mesh. Outputs the distance, - // the index of the triangle and the closest point in mesh coordinate space. - si_result signed_distance(const Vec3d& p) const; - - bool inside(const Vec3d& p) const; -}; - using PointSet = Eigen::MatrixXd; //EigenMesh3D to_eigenmesh(const TriangleMesh& m); @@ -193,7 +116,7 @@ using PointSet = Eigen::MatrixXd; //EigenMesh3D to_eigenmesh(const ModelObject& model); // Simple conversion of 'vector of points' to an Eigen matrix -PointSet to_point_set(const std::vector&); +PointSet to_point_set(const std::vector&); /* ************************************************************************** */ diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index d3af1eac8..25638fe69 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -95,7 +95,9 @@ size_t SpatIndex::size() const class EigenMesh3D::AABBImpl: public igl::AABB { public: +#ifdef SLIC3R_SLA_NEEDS_WINDTREE igl::WindingNumberAABB windtree; +#endif /* SLIC3R_SLA_NEEDS_WINDTREE */ }; EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) { @@ -136,7 +138,9 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) { // Build the AABB accelaration tree m_aabb->init(m_V, m_F); +#ifdef SLIC3R_SLA_NEEDS_WINDTREE m_aabb->windtree.set_mesh(m_V, m_F); +#endif /* SLIC3R_SLA_NEEDS_WINDTREE */ } EigenMesh3D::~EigenMesh3D() {} @@ -168,6 +172,7 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const return ret; } +#ifdef SLIC3R_SLA_NEEDS_WINDTREE EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const { double sign = 0; double sqdst = 0; int i = 0; Vec3d c; igl::signed_distance_winding_number(*m_aabb, m_V, m_F, m_aabb->windtree, @@ -179,6 +184,7 @@ EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const { bool EigenMesh3D::inside(const Vec3d &p) const { return m_aabb->windtree.inside(p); } +#endif /* SLIC3R_SLA_NEEDS_WINDTREE */ /* **************************************************************************** * Misc functions @@ -199,9 +205,11 @@ template double distance(const Vec& pp1, const Vec& pp2) { return std::sqrt(p.transpose() * p); } -PointSet normals(const PointSet& points, const EigenMesh3D& mesh, +PointSet normals(const PointSet& points, + const EigenMesh3D& mesh, double eps, - std::function throw_on_cancel) { + std::function throw_on_cancel) +{ if(points.rows() == 0 || mesh.V().rows() == 0 || mesh.F().rows() == 0) return {}; @@ -222,7 +230,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& mesh, const Vec3d& p3 = mesh.V().row(trindex(2)); // We should check if the point lies on an edge of the hosting triangle. - // If it does than all the other triangles using the same two points + // If it does then all the other triangles using the same two points // have to be searched and the final normal should be some kind of // aggregation of the participating triangle normals. We should also // consider the cases where the support point lies right on a vertex diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 142428f1d..23880cfa9 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -2,12 +2,14 @@ #include "SLA/SLASupportTree.hpp" #include "SLA/SLABasePool.hpp" #include "SLA/SLAAutoSupports.hpp" +#include "ClipperUtils.hpp" #include "MTUtils.hpp" #include #include #include +#include #include //#include //#include "tbb/mutex.h" @@ -25,7 +27,7 @@ using SupportTreePtr = std::unique_ptr; class SLAPrintObject::SupportData { public: sla::EigenMesh3D emesh; // index-triangle representation - sla::PointSet support_points; // all the support points (manual/auto) + std::vector support_points; // all the support points (manual/auto) SupportTreePtr support_tree_ptr; // the supports SlicedSupports support_slices; // sliced supports std::vector level_ids; @@ -51,7 +53,7 @@ const std::array OBJ_STEP_LABELS = L("Slicing model"), // slaposObjectSlice, L("Generating support points"), // slaposSupportPoints, L("Generating support tree"), // slaposSupportTree, - L("Generating base pool"), // slaposBasePool, + L("Generating pad"), // slaposBasePool, L("Slicing supports"), // slaposSliceSupports, L("Slicing supports") // slaposIndexSlices, }; @@ -182,7 +184,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf if (model.id() != m_model.id()) { // Kill everything, initialize from scratch. // Stop background processing. - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(this->invalidate_all_steps()); for (SLAPrintObject *object : m_objects) { model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); @@ -211,7 +213,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf } else { // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(this->invalidate_step(slapsRasterize)); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); @@ -308,7 +310,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id()) it_print_object_status = print_object_status.end(); // Check whether a model part volume was added or removed, their transformations or order changed. - bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::MODEL_PART); + bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); bool sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() || (! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new))); if (model_parts_differ || sla_trafo_differs) { @@ -335,11 +337,34 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf } } } - if (model_object.sla_support_points != model_object_new.sla_support_points) { + /*if (model_object.sla_support_points != model_object_new.sla_support_points) { model_object.sla_support_points = model_object_new.sla_support_points; if (it_print_object_status != print_object_status.end()) update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); } + if (model_object.sla_points_status != model_object_new.sla_points_status) { + // Change of this status should invalidate support points. The points themselves are not enough, there are none + // in case that nothing was generated OR that points were autogenerated already and not copied to the front-end. + // These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT + // invalidate - that would keep stopping the background processing without a reason. + if (model_object.sla_points_status != sla::PointsStatus::Generating) + if (it_print_object_status != print_object_status.end()) + update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); + model_object.sla_points_status = model_object_new.sla_points_status; + }*/ + + bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified; + bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified; + if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports + (! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports + (new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) { + if (it_print_object_status != print_object_status.end()) + update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); + + model_object.sla_points_status = model_object_new.sla_points_status; + model_object.sla_support_points = model_object_new.sla_support_points; + } + // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; @@ -354,14 +379,18 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf std::vector new_instances = sla_instances(model_object); if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) { // The SLAPrintObject is already there. - if (new_instances != it_print_object_status->print_object->instances()) { - // Instances changed. - it_print_object_status->print_object->set_instances(new_instances); - update_apply_status(this->invalidate_step(slapsRasterize)); - } - print_objects_new.emplace_back(it_print_object_status->print_object); - const_cast(*it_print_object_status).status = PrintObjectStatus::Reused; - } else { + if (new_instances.empty()) { + const_cast(*it_print_object_status).status = PrintObjectStatus::Deleted; + } else { + if (new_instances != it_print_object_status->print_object->instances()) { + // Instances changed. + it_print_object_status->print_object->set_instances(new_instances); + update_apply_status(this->invalidate_step(slapsRasterize)); + } + print_objects_new.emplace_back(it_print_object_status->print_object); + const_cast(*it_print_object_status).status = PrintObjectStatus::Reused; + } + } else if (! new_instances.empty()) { auto print_object = new SLAPrintObject(this, &model_object); // FIXME: this invalidates the transformed mesh in SLAPrintObject @@ -376,7 +405,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf } if (m_objects != print_objects_new) { - this->call_cancell_callback(); + this->call_cancel_callback(); update_apply_status(this->invalidate_all_steps()); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. @@ -398,6 +427,113 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf return static_cast(apply_status); } +// After calling the apply() function, set_task() may be called to limit the task to be processed by process(). +void SLAPrint::set_task(const TaskParams ¶ms) +{ + // Grab the lock for the Print / PrintObject milestones. + tbb::mutex::scoped_lock lock(this->state_mutex()); + + int n_object_steps = int(params.to_object_step) + 1; + if (n_object_steps == 0) + n_object_steps = (int)slaposCount; + + if (params.single_model_object.valid()) { + // Find the print object to be processed with priority. + SLAPrintObject *print_object = nullptr; + size_t idx_print_object = 0; + for (; idx_print_object < m_objects.size(); ++ idx_print_object) + if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) { + print_object = m_objects[idx_print_object]; + break; + } + assert(print_object != nullptr); + // Find out whether the priority print object is being currently processed. + bool running = false; + for (int istep = 0; istep < n_object_steps; ++ istep) { + if (! print_object->m_stepmask[istep]) + // Step was skipped, cancel. + break; + if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) { + // No step was skipped, and a wanted step is being processed. Don't cancel. + running = true; + break; + } + } + if (! running) + this->call_cancel_callback(); + + // Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway. + if (params.single_model_instance_only) { + // Suppress all the steps of other instances. + for (SLAPrintObject *po : m_objects) + for (int istep = 0; istep < (int)slaposCount; ++ istep) + po->m_stepmask[istep] = false; + } else if (! running) { + // Swap the print objects, so that the selected print_object is first in the row. + // At this point the background processing must be stopped, so it is safe to shuffle print objects. + if (idx_print_object != 0) + std::swap(m_objects.front(), m_objects[idx_print_object]); + } + // and set the steps for the current object. + for (int istep = 0; istep < n_object_steps; ++ istep) + print_object->m_stepmask[istep] = true; + for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep) + print_object->m_stepmask[istep] = false; + } else { + // Slicing all objects. + bool running = false; + for (SLAPrintObject *print_object : m_objects) + for (int istep = 0; istep < n_object_steps; ++ istep) { + if (! print_object->m_stepmask[istep]) { + // Step may have been skipped. Restart. + goto loop_end; + } + if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) { + // This step is running, and the state cannot be changed due to the this->state_mutex() being locked. + // It is safe to manipulate m_stepmask of other SLAPrintObjects and SLAPrint now. + running = true; + goto loop_end; + } + } + loop_end: + if (! running) + this->call_cancel_callback(); + for (SLAPrintObject *po : m_objects) { + for (int istep = 0; istep < n_object_steps; ++ istep) + po->m_stepmask[istep] = true; + for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep) + po->m_stepmask[istep] = false; + } + } + + if (params.to_object_step != -1 || params.to_print_step != -1) { + // Limit the print steps. + size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1; + for (; istep < m_stepmask.size(); ++ istep) + m_stepmask[istep] = false; + } +} + +// Clean up after process() finished, either with success, error or if canceled. +// The adjustments on the SLAPrint / SLAPrintObject data due to set_task() are to be reverted here. +void SLAPrint::finalize() +{ + for (SLAPrintObject *po : m_objects) + for (int istep = 0; istep < (int)slaposCount; ++ istep) + po->m_stepmask[istep] = true; + for (int istep = 0; istep < (int)slapsCount; ++ istep) + m_stepmask[istep] = true; +} + +// Generate a recommended output file name based on the format template, default extension, and template parameters +// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics. +// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before the output is finalized). +std::string SLAPrint::output_filename() const +{ + DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); + return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "sl1", &config); +} + namespace { // Compile the argument for support creation from the static print config. sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { @@ -472,7 +608,7 @@ void SLAPrint::process() const size_t objcount = m_objects.size(); const unsigned min_objstatus = 0; // where the per object operations start - const unsigned max_objstatus = 80; // where the per object operations end + const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsRasterize]; // where the per object operations end // the coefficient that multiplies the per object status values which // are set up for <0, 100>. They need to be scaled into the whole process @@ -501,7 +637,7 @@ void SLAPrint::process() ilh, float(lh)); auto& layers = po.m_model_slices; layers.clear(); - slicer.slice(heights, &layers, [this](){ throw_if_canceled(); }); + slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); }); }; // In this step we check the slices, identify island and cover them with @@ -517,10 +653,11 @@ void SLAPrint::process() BOOST_LOG_TRIVIAL(debug) << "Support point count " << mo.sla_support_points.size(); - // If there are no points on the front-end, we will do the - // autoplacement. Otherwise we will just blindly copy the frontend data + // Unless the user modified the points or we already did the calculation, we will do + // the autoplacement. Otherwise we will just blindly copy the frontend data // into the backend cache. - if(mo.sla_support_points.empty()) { + if (mo.sla_points_status != sla::PointsStatus::UserModified) { + // calculate heights of slices (slices are calculated already) double lh = po.m_config.layer_height.getFloat(); @@ -532,9 +669,10 @@ void SLAPrint::process() this->throw_if_canceled(); SLAAutoSupports::Config config; const SLAPrintObjectConfig& cfg = po.config(); - config.minimal_z = float(cfg.support_minimal_z); - config.density_at_45 = cfg.support_density_at_45 / 10000.f; - config.density_at_horizontal = cfg.support_density_at_horizontal / 10000.f; + + // the density config value is in percents: + config.density_relative = float(cfg.support_points_density_relative / 100.f); + config.minimal_distance = float(cfg.support_points_minimal_distance); // Construction of this object does the calculation. this->throw_if_canceled(); @@ -546,17 +684,19 @@ void SLAPrint::process() [this]() { throw_if_canceled(); }); // Now let's extract the result. - const std::vector& points = auto_supports.output(); + const std::vector& points = auto_supports.output(); this->throw_if_canceled(); - po.m_supportdata->support_points = sla::to_point_set(points); + po.m_supportdata->support_points = points; BOOST_LOG_TRIVIAL(debug) << "Automatic support points: " - << po.m_supportdata->support_points.rows(); + << po.m_supportdata->support_points.size(); + + // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass the update status to GLGizmoSlaSupports + report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { - // There are some points on the front-end, no calculation will be done. - po.m_supportdata->support_points = - sla::to_point_set(po.transformed_support_points()); + // There are either some points on the front-end, or the user removed them on purpose. No calculation will be done. + po.m_supportdata->support_points = po.transformed_support_points(); } }; @@ -587,6 +727,8 @@ void SLAPrint::process() ctl.statuscb = [this, init, d](unsigned st, const std::string& msg) { + //FIXME this status line scaling does not seem to be correct. + // How does it account for an increasing object index? report_status(*this, int(init + st*d), msg); }; @@ -594,7 +736,7 @@ void SLAPrint::process() ctl.cancelfn = [this]() { throw_if_canceled(); }; po.m_supportdata->support_tree_ptr.reset( - new SLASupportTree(po.m_supportdata->support_points, + new SLASupportTree(sla::to_point_set(po.m_supportdata->support_points), po.m_supportdata->emesh, scfg, ctl)); // Create the unified mesh @@ -605,7 +747,7 @@ void SLAPrint::process() po.m_supportdata->support_tree_ptr->merged_mesh(); BOOST_LOG_TRIVIAL(debug) << "Processed support point count " - << po.m_supportdata->support_points.rows(); + << po.m_supportdata->support_points.size(); // Check the mesh for later troubleshooting. if(po.support_mesh().empty()) @@ -635,11 +777,13 @@ void SLAPrint::process() double wt = po.m_config.pad_wall_thickness.getFloat(); double h = po.m_config.pad_wall_height.getFloat(); double md = po.m_config.pad_max_merge_distance.getFloat(); - double er = po.m_config.pad_edge_radius.getFloat(); + // Radius is disabled for now... + double er = 0; // po.m_config.pad_edge_radius.getFloat(); + double tilt = po.m_config.pad_wall_slope.getFloat() * PI / 180.0; double lh = po.m_config.layer_height.getFloat(); double elevation = po.m_config.support_object_elevation.getFloat(); if(!po.m_config.supports_enable.getBool()) elevation = 0; - sla::PoolConfig pcfg(wt, h, md, er); + sla::PoolConfig pcfg(wt, h, md, er, tilt); ExPolygons bp; double pad_h = sla::get_pad_fullheight(pcfg); @@ -650,8 +794,7 @@ void SLAPrint::process() if(elevation < pad_h) { // we have to count with the model geometry for the base plate - sla::base_plate(trmesh, bp, float(pad_h), float(lh), - thrfn); + sla::base_plate(trmesh, bp, float(pad_h), float(lh), thrfn); } pcfg.throw_on_cancel = thrfn; @@ -878,21 +1021,20 @@ void SLAPrint::process() // Print all the layers in parallel tbb::parallel_for(0, lvlcnt, lvlfn); + + // Fill statistics + this->fill_statistics(); + // Set statistics values to the printer + m_printer->set_statistics({(m_print_statistics.objects_used_material + m_print_statistics.support_used_material)/1000, + double(m_default_object_config.faded_layers.getInt()), + double(m_print_statistics.slow_layers_count), + double(m_print_statistics.fast_layers_count) + }); }; using slaposFn = std::function; using slapsFn = std::function; - // This is the actual order of steps done on each PrintObject - std::array objectsteps = { - slaposObjectSlice, // SupportPoints will need this step - slaposSupportPoints, - slaposSupportTree, - slaposBasePool, - slaposSliceSupports, - slaposIndexSlices - }; - std::array pobj_program = { slice_model, @@ -916,28 +1058,32 @@ void SLAPrint::process() // TODO: this loop could run in parallel but should not exhaust all the CPU // power available - for(SLAPrintObject * po : m_objects) { + // Calculate the support structures first before slicing the supports, so that the preview will get displayed ASAP for all objects. + std::vector step_ranges = { slaposObjectSlice, slaposSliceSupports, slaposCount }; + for (size_t idx_range = 0; idx_range + 1 < step_ranges.size(); ++ idx_range) { + for(SLAPrintObject * po : m_objects) { - BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name; + BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name; - for(size_t s = 0; s < objectsteps.size(); ++s) { - auto currentstep = objectsteps[s]; + for (int s = (int)step_ranges[idx_range]; s < (int)step_ranges[idx_range + 1]; ++s) { + auto currentstep = (SLAPrintObjectStep)s; - // Cancellation checking. Each step will check for cancellation - // on its own and return earlier gracefully. Just after it returns - // execution gets to this point and throws the canceled signal. - throw_if_canceled(); - - st += unsigned(incr * ostepd); - - if(po->m_stepmask[currentstep] && po->set_started(currentstep)) { - report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]); - pobj_program[currentstep](*po); + // Cancellation checking. Each step will check for cancellation + // on its own and return earlier gracefully. Just after it returns + // execution gets to this point and throws the canceled signal. throw_if_canceled(); - po->set_done(currentstep); - } - incr = OBJ_STEP_LEVELS[currentstep]; + st += unsigned(incr * ostepd); + + if(po->m_stepmask[currentstep] && po->set_started(currentstep)) { + report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]); + pobj_program[currentstep](*po); + throw_if_canceled(); + po->set_done(currentstep); + } + + incr = OBJ_STEP_LEVELS[currentstep]; + } } } @@ -994,7 +1140,10 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps; @@ -1027,6 +1176,166 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector& instances) { + const size_t inst_cnt = instances.size(); + + size_t polygon_cnt = 0; + for (const ExPolygon& polygon : input_polygons) + polygon_cnt += polygon.holes.size() + 1; + + Polygons polygons; + polygons.reserve(polygon_cnt * inst_cnt); + for (const ExPolygon& polygon : input_polygons) { + for (size_t i = 0; i < inst_cnt; ++i) + { + ExPolygon tmp = polygon; + tmp.rotate(Geometry::rad2deg(instances[i].rotation)); + tmp.translate(instances[i].shift.x(), instances[i].shift.y()); + polygons_append(polygons, to_polygons(std::move(tmp))); + } + } + return polygons; + }; + + double supports_volume = 0.0; + double models_volume = 0.0; + + double estim_time = 0.0; + + size_t slow_layers = 0; + size_t fast_layers = 0; + + // find highest object + // Which is a better bet? To compare by max_z or by number of layers in the index? + double max_z = 0.; + size_t max_layers_cnt = 0; + size_t highest_obj_idx = 0; + for (SLAPrintObject *&po : m_objects) { + const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index(); + if (! slice_index.empty()) { + double z = (-- slice_index.end())->first; + size_t cnt = slice_index.size(); + //if (z > max_z) { + if (cnt > max_layers_cnt) { + max_layers_cnt = cnt; + max_z = z; + highest_obj_idx = &po - &m_objects.front(); + } + } + } + + const SLAPrintObject * highest_obj = m_objects[highest_obj_idx]; + const SLAPrintObject::SliceIndex& highest_obj_slice_index = highest_obj->get_slice_index(); + + const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); + double fade_layer_time = init_exp_time; + + int sliced_layer_cnt = 0; + for (const auto& layer : highest_obj_slice_index) + { + const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height; + + // Calculation of the consumed material + + Polygons model_polygons; + Polygons supports_polygons; + + for (SLAPrintObject * po : m_objects) + { + const SLAPrintObject::SliceRecord *record = nullptr; + { + const SLAPrintObject::SliceIndex& index = po->get_slice_index(); + auto key = layer.first; + const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON)); + if (it_key == index.end() || it_key->first > key + EPSILON) + continue; + record = &it_key->second; + } + + if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE) + append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances())); + + if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE) + append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances())); + } + + model_polygons = union_(model_polygons); + double layer_model_area = 0; + for (const Polygon& polygon : model_polygons) + layer_model_area += polygon.area(); + + if (layer_model_area != 0) + models_volume += layer_model_area * l_height; + + if (!supports_polygons.empty() && !model_polygons.empty()) + supports_polygons = diff(supports_polygons, model_polygons); + double layer_support_area = 0; + for (const Polygon& polygon : supports_polygons) + layer_support_area += polygon.area(); + + if (layer_support_area != 0) + supports_volume += layer_support_area * l_height; + + // Calculation of the slow and fast layers to the future controlling those values on FW + + const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; + const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt; + if (is_fast_layer) + fast_layers++; + else + slow_layers++; + + + // Calculation of the printing time + + if (sliced_layer_cnt < 3) + estim_time += init_exp_time; + else if (fade_layer_time > exp_time) + { + fade_layer_time -= delta_fade_time; + estim_time += fade_layer_time; + } + else + estim_time += exp_time; + + estim_time += tilt_time; + + sliced_layer_cnt++; + } + + m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; + m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; + + // Estimated printing time + // A layers count o the highest object + if (max_layers_cnt == 0) + m_print_statistics.estimated_print_time = "N/A"; + else + m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time)); + + m_print_statistics.fast_layers_count = fast_layers; + m_print_statistics.slow_layers_count = slow_layers; +} + // Returns true if an object step is done on all objects and there's at least one object. bool SLAPrint::is_step_done(SLAPrintObjectStep step) const { @@ -1034,7 +1343,7 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const return false; tbb::mutex::scoped_lock lock(this->state_mutex()); for (const SLAPrintObject *object : m_objects) - if (! object->m_state.is_done_unguarded(step)) + if (! object->is_step_done_unguarded(step)) return false; return true; } @@ -1060,9 +1369,14 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector steps; bool invalidated = false; for (const t_config_option_key &opt_key : opt_keys) { - if (opt_key == "layer_height") { + if ( opt_key == "layer_height" + || opt_key == "faded_layers" + || opt_key == "slice_closing_radius") { steps.emplace_back(slaposObjectSlice); - } else if (opt_key == "supports_enable") { + } else if ( + opt_key == "supports_enable" + || opt_key == "support_points_density_relative" + || opt_key == "support_points_minimal_distance") { steps.emplace_back(slaposSupportPoints); } else if ( opt_key == "support_head_front_diameter" @@ -1082,6 +1396,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector EMPTY_SLICES; const TriangleMesh EMPTY_MESH; } -const Eigen::MatrixXd& SLAPrintObject::get_support_points() const +const std::vector& SLAPrintObject::get_support_points() const { return m_supportdata->support_points; } @@ -1244,17 +1559,60 @@ const TriangleMesh &SLAPrintObject::transformed_mesh() const { return m_transformed_rmesh.get(); } -std::vector SLAPrintObject::transformed_support_points() const +std::vector SLAPrintObject::transformed_support_points() const { assert(m_model_object != nullptr); - auto& spts = m_model_object->sla_support_points; + std::vector& spts = m_model_object->sla_support_points; // this could be cached as well - std::vector ret; ret.reserve(spts.size()); + std::vector ret; + ret.reserve(spts.size()); - for(auto& sp : spts) ret.emplace_back( trafo() * Vec3d(sp.cast())); + for(sla::SupportPoint& sp : spts) { + Vec3d transformed_pos = trafo() * Vec3d(sp.pos(0), sp.pos(1), sp.pos(2)); + ret.emplace_back(transformed_pos(0), transformed_pos(1), transformed_pos(2), sp.head_front_radius, sp.is_new_island); + } return ret; } +DynamicConfig SLAPrintStatistics::config() const +{ + DynamicConfig config; + const std::string print_time = Slic3r::short_time(this->estimated_print_time); + config.set_key_value("print_time", new ConfigOptionString(print_time)); + config.set_key_value("objects_used_material", new ConfigOptionFloat(this->objects_used_material)); + config.set_key_value("support_used_material", new ConfigOptionFloat(this->support_used_material)); + config.set_key_value("total_cost", new ConfigOptionFloat(this->total_cost)); + config.set_key_value("total_weight", new ConfigOptionFloat(this->total_weight)); + return config; +} + +DynamicConfig SLAPrintStatistics::placeholders() +{ + DynamicConfig config; + for (const std::string &key : { + "print_time", "total_cost", "total_weight", + "objects_used_material", "support_used_material" }) + config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}")); + return config; +} + +std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) const +{ + std::string final_path; + try { + boost::filesystem::path path(path_in); + DynamicConfig cfg = this->config(); + PlaceholderParser pp; + std::string new_stem = pp.process(path.stem().string(), 0, &cfg); + final_path = (path.parent_path() / (new_stem + path.extension().string())).string(); + } + catch (const std::exception &ex) { + BOOST_LOG_TRIVIAL(error) << "Failed to apply the print statistics to the export file name: " << ex.what(); + final_path = path_in; + } + return final_path; +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 21503c6f6..4ac17f7b5 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -2,7 +2,6 @@ #define slic3r_SLAPrint_hpp_ #include - #include "PrintBase.hpp" #include "PrintExport.hpp" #include "Point.hpp" @@ -70,7 +69,7 @@ public: // This will return the transformed mesh which is cached const TriangleMesh& transformed_mesh() const; - std::vector transformed_support_points() const; + std::vector transformed_support_points() const; // Get the needed Z elevation for the model geometry if supports should be // displayed. This Z offset should also be applied to the support @@ -91,7 +90,7 @@ public: const std::vector& get_support_slices() const; // This method returns the support points of this SLAPrintObject. - const Eigen::MatrixXd& get_support_points() const; + const std::vector& get_support_points() const; // An index record referencing the slices // (get_model_slices(), get_support_slices()) where the keys are the height @@ -139,6 +138,10 @@ protected: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); + // Which steps have to be performed. Implicitly: all + // to be accessible from SLAPrint + std::vector m_stepmask; + private: // Object specific configuration, pulled from the configuration layer. SLAPrintObjectConfig m_config; @@ -146,9 +149,6 @@ private: Transform3d m_trafo = Transform3d::Identity(); std::vector m_instances; - // Which steps have to be performed. Implicitly: all - std::vector m_stepmask; - // Individual 2d slice polygons from lower z to higher z levels std::vector m_model_slices; @@ -171,6 +171,35 @@ using PrintObjects = std::vector; class TriangleMesh; +struct SLAPrintStatistics +{ + SLAPrintStatistics() { clear(); } + std::string estimated_print_time; + double objects_used_material; + double support_used_material; + size_t slow_layers_count; + size_t fast_layers_count; + double total_cost; + double total_weight; + + // Config with the filled in print statistics. + DynamicConfig config() const; + // Config with the statistics keys populated with placeholder strings. + static DynamicConfig placeholders(); + // Replace the print statistics placeholders in the path. + std::string finalize_output_path(const std::string &path_in) const; + + void clear() { + estimated_print_time.clear(); + objects_used_material = 0.; + support_used_material = 0.; + slow_layers_count = 0; + fast_layers_count = 0; + total_cost = 0.; + total_weight = 0.; + } +}; + /** * @brief This class is the high level FSM for the SLA printing process. * @@ -194,7 +223,9 @@ public: void clear() override; bool empty() const override { return m_objects.empty(); } ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; + void set_task(const TaskParams ¶ms) override; void process() override; + void finalize() override; // Returns true if an object step is done on all objects and there's at least one object. bool is_step_done(SLAPrintObjectStep step) const; // Returns true if the last step was finished with success. @@ -205,8 +236,9 @@ public: } const PrintObjects& objects() const { return m_objects; } - std::string output_filename() const override - { return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "zip"); } + std::string output_filename() const override; + + const SLAPrintStatistics& print_statistics() const { return m_print_statistics; } private: using SLAPrinter = FilePrinter; @@ -215,6 +247,8 @@ private: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); + void fill_statistics(); + SLAPrintConfig m_print_config; SLAPrinterConfig m_printer_config; SLAMaterialConfig m_material_config; @@ -246,6 +280,9 @@ private: // The printer itself SLAPrinterPtr m_printer; + // Estimated print time, material consumed. + SLAPrintStatistics m_print_statistics; + friend SLAPrintObject; }; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 8d788ed51..755ca5ffa 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -23,21 +23,10 @@ // Scene's GUI made using imgui library #define ENABLE_IMGUI (1 && ENABLE_1_42_0_ALPHA1) #define DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI (1 && ENABLE_IMGUI) -// Modified Sla support gizmo -#define ENABLE_SLA_SUPPORT_GIZMO_MOD (1 && ENABLE_1_42_0_ALPHA1) // Use wxDataViewRender instead of wxDataViewCustomRenderer #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1) -//==================== -// 1.42.0.alpha2 techs -//==================== -#define ENABLE_1_42_0_ALPHA2 1 - -// Adds print bed models to 3D scene -#define ENABLE_PRINT_BED_MODELS (1 && ENABLE_1_42_0_ALPHA2) - - //==================== // 1.42.0.alpha4 techs //==================== @@ -49,10 +38,6 @@ #define ENABLE_MOVE_MIN_THRESHOLD (1 && ENABLE_1_42_0_ALPHA4) // Modified initial default placement of generic subparts #define ENABLE_GENERIC_SUBPARTS_PLACEMENT (1 && ENABLE_1_42_0_ALPHA4) -// Reworked management of bed shape changes -#define ENABLE_REWORKED_BED_SHAPE_CHANGE (1 && ENABLE_1_42_0_ALPHA4) -// Use anisotropic filtering on bed plate texture -#define ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES (1 && ENABLE_1_42_0_ALPHA4) // Bunch of fixes related to volumes centering #define ENABLE_VOLUMES_CENTERING_FIXES (1 && ENABLE_1_42_0_ALPHA4) @@ -65,4 +50,13 @@ // Toolbar items hidden/shown in dependence of the user mode #define ENABLE_MODE_AWARE_TOOLBAR_ITEMS (1 && ENABLE_1_42_0_ALPHA5) + +//==================== +// 1.42.0.alpha7 techs +//==================== +#define ENABLE_1_42_0_ALPHA7 1 + +// Printbed textures generated from svg files +#define ENABLE_TEXTURES_FROM_SVG (1 && ENABLE_1_42_0_ALPHA7) + #endif // _technologies_h_ diff --git a/src/libslic3r/Tesselate.cpp b/src/libslic3r/Tesselate.cpp index f4ce0703d..febb3d0e7 100644 --- a/src/libslic3r/Tesselate.cpp +++ b/src/libslic3r/Tesselate.cpp @@ -20,7 +20,7 @@ public: gluDeleteTess(m_tesselator); } - Pointf3s tesselate(const ExPolygon &expoly, double z_, bool flipped_) + std::vector tesselate3d(const ExPolygon &expoly, double z_, bool flipped_) { m_z = z_; m_flipped = flipped_; @@ -56,7 +56,7 @@ public: return std::move(m_output_triangles); } - Pointf3s tesselate(const ExPolygons &expolygons, double z_, bool flipped_) + std::vector tesselate3d(const ExPolygons &expolygons, double z_, bool flipped_) { m_z = z_; m_flipped = flipped_; @@ -189,16 +189,60 @@ private: bool m_flipped; }; -Pointf3s triangulate_expolygons_3df(const ExPolygon &poly, coordf_t z, bool flip) +std::vector triangulate_expolygon_3d(const ExPolygon &poly, coordf_t z, bool flip) { GluTessWrapper tess; - return tess.tesselate(poly, z, flip); + return tess.tesselate3d(poly, z, flip); } -Pointf3s triangulate_expolygons_3df(const ExPolygons &polys, coordf_t z, bool flip) +std::vector triangulate_expolygons_3d(const ExPolygons &polys, coordf_t z, bool flip) { GluTessWrapper tess; - return tess.tesselate(polys, z, flip); + return tess.tesselate3d(polys, z, flip); +} + +std::vector triangulate_expolygon_2d(const ExPolygon &poly, bool flip) +{ + GluTessWrapper tess; + std::vector triangles = tess.tesselate3d(poly, 0, flip); + std::vector out; + out.reserve(triangles.size()); + for (const Vec3d &pt : triangles) + out.emplace_back(pt.x(), pt.y()); + return out; +} + +std::vector triangulate_expolygons_2d(const ExPolygons &polys, bool flip) +{ + GluTessWrapper tess; + std::vector triangles = tess.tesselate3d(polys, 0, flip); + std::vector out; + out.reserve(triangles.size()); + for (const Vec3d &pt : triangles) + out.emplace_back(pt.x(), pt.y()); + return out; +} + +std::vector triangulate_expolygon_2f(const ExPolygon &poly, bool flip) +{ + GluTessWrapper tess; + std::vector triangles = tess.tesselate3d(poly, 0, flip); + std::vector out; + out.reserve(triangles.size()); + for (const Vec3d &pt : triangles) + out.emplace_back(float(pt.x()), float(pt.y())); + return out; +} + +std::vector triangulate_expolygons_2f(const ExPolygons &polys, bool flip) +{ + GluTessWrapper tess; + std::vector triangles = tess.tesselate3d(polys, 0, flip); + std::vector out; + out.reserve(triangles.size()); + for (const Vec3d &pt : triangles) + out.emplace_back(float(pt.x()), float(pt.y())); + return out; } } // namespace Slic3r diff --git a/src/libslic3r/Tesselate.hpp b/src/libslic3r/Tesselate.hpp index ed12df888..02e86eb33 100644 --- a/src/libslic3r/Tesselate.hpp +++ b/src/libslic3r/Tesselate.hpp @@ -10,8 +10,12 @@ namespace Slic3r { class ExPolygon; typedef std::vector ExPolygons; -extern Pointf3s triangulate_expolygons_3df(const ExPolygon &poly, coordf_t z = 0, bool flip = false); -extern Pointf3s triangulate_expolygons_3df(const ExPolygons &polys, coordf_t z = 0, bool flip = false); +extern std::vector triangulate_expolygon_3d (const ExPolygon &poly, coordf_t z = 0, bool flip = false); +extern std::vector triangulate_expolygons_3d(const ExPolygons &polys, coordf_t z = 0, bool flip = false); +extern std::vector triangulate_expolygon_2d (const ExPolygon &poly, bool flip = false); +extern std::vector triangulate_expolygons_2d(const ExPolygons &polys, bool flip = false); +extern std::vector triangulate_expolygon_2f (const ExPolygon &poly, bool flip = false); +extern std::vector triangulate_expolygons_2f(const ExPolygons &polys, bool flip = false); } // namespace Slic3r diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 1236209d4..785d9005c 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -852,7 +852,7 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector &z, std::vector* layers, throw_on_cancel_callback_type throw_on_cancel) const +void TriangleMeshSlicer::slice(const std::vector &z, const float closing_radius, std::vector* layers, throw_on_cancel_callback_type throw_on_cancel) const { std::vector layers_p; this->slice(z, &layers_p, throw_on_cancel); @@ -861,13 +861,13 @@ void TriangleMeshSlicer::slice(const std::vector &z, std::vectorresize(z.size()); tbb::parallel_for( tbb::blocked_range(0, z.size()), - [&layers_p, layers, throw_on_cancel, this](const tbb::blocked_range& range) { + [&layers_p, closing_radius, layers, throw_on_cancel, this](const tbb::blocked_range& range) { for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { #ifdef SLIC3R_TRIANGLEMESH_DEBUG printf("Layer " PRINTF_ZU " (slice_z = %.2f):\n", layer_id, z[layer_id]); #endif throw_on_cancel(); - this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]); + this->make_expolygons(layers_p[layer_id], closing_radius, &(*layers)[layer_id]); } }); BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - end"; @@ -1600,7 +1600,7 @@ void TriangleMeshSlicer::make_expolygons_simple(std::vector &l #endif } -void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) const +void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const { /* Input loops are not suitable for evenodd nor nonzero fill types, as we might get @@ -1655,7 +1655,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic // 0.0499 comes from https://github.com/slic3r/Slic3r/issues/959 // double safety_offset = scale_(0.0499); // 0.0001 is set to satisfy GH #520, #1029, #1364 -// double safety_offset = scale_(0.0001); // now a config value + double safety_offset = scale_(closing_radius); /* The following line is commented out because it can generate wrong polygons, see for example issue #661 */ @@ -1670,17 +1670,17 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic #endif // append to the supplied collection - /* Fix for issue #661 { */ + if (safety_offset > 0) expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset)); - //expolygons_append(*slices, ex_slices); - /* } */ + else + expolygons_append(*slices, union_ex(loops, false)); } -void TriangleMeshSlicer::make_expolygons(std::vector &lines, ExPolygons* slices) const +void TriangleMeshSlicer::make_expolygons(std::vector &lines, const float closing_radius, ExPolygons* slices) const { Polygons pp; this->make_loops(lines, &pp); - this->make_expolygons(pp, slices); + this->make_expolygons(pp, closing_radius, slices); } void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const @@ -1781,7 +1781,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating upper part"; ExPolygons section; this->make_expolygons_simple(upper_lines, §ion); - Pointf3s triangles = triangulate_expolygons_3df(section, z, true); + Pointf3s triangles = triangulate_expolygons_3d(section, z, true); stl_facet facet; facet.normal = stl_normal(0, 0, -1.f); for (size_t i = 0; i < triangles.size(); ) { @@ -1795,7 +1795,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating lower part"; ExPolygons section; this->make_expolygons_simple(lower_lines, §ion); - Pointf3s triangles = triangulate_expolygons_3df(section, z, false); + Pointf3s triangles = triangulate_expolygons_3d(section, z, false); stl_facet facet; facet.normal = stl_normal(0, 0, -1.f); for (size_t i = 0; i < triangles.size(); ) { diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 2ad36e639..04c13e876 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -165,7 +165,7 @@ public: TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); } void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel); void slice(const std::vector &z, std::vector* layers, throw_on_cancel_callback_type throw_on_cancel) const; - void slice(const std::vector &z, std::vector* layers, throw_on_cancel_callback_type throw_on_cancel) const; + void slice(const std::vector &z, const float closing_radius, std::vector* layers, throw_on_cancel_callback_type throw_on_cancel) const; enum FacetSliceType { NoSlice = 0, Slicing = 1, @@ -175,7 +175,6 @@ public: const float min_z, const float max_z, IntersectionLine *line_out) const; void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const; - double safety_offset = scale_(0.02); private: const TriangleMesh *mesh; // Map from a facet to an edge index. @@ -185,9 +184,9 @@ private: void _slice_do(size_t facet_idx, std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const; void make_loops(std::vector &lines, Polygons* loops) const; - void make_expolygons(const Polygons &loops, ExPolygons* slices) const; + void make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const; void make_expolygons_simple(std::vector &lines, ExPolygons* slices) const; - void make_expolygons(std::vector &lines, ExPolygons* slices) const; + void make_expolygons(std::vector &lines, const float closing_radius, ExPolygons* slices) const; }; TriangleMesh make_cube(double x, double y, double z); diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 046745e6f..c13df4546 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -206,6 +206,69 @@ public: void reset() { closure = Closure(); } }; +// Shorten the dhms time by removing the seconds, rounding the dhm to full minutes +// and removing spaces. +static std::string short_time(const std::string &time) +{ + // Parse the dhms time format. + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + if (time.find('d') != std::string::npos) + ::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds); + else if (time.find('h') != std::string::npos) + ::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds); + else if (time.find('m') != std::string::npos) + ::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds); + else if (time.find('s') != std::string::npos) + ::sscanf(time.c_str(), "%ds", &seconds); + // Round to full minutes. + if (days + hours + minutes > 0 && seconds >= 30) { + if (++minutes == 60) { + minutes = 0; + if (++hours == 24) { + hours = 0; + ++days; + } + } + } + // Format the dhm time. + char buffer[64]; + if (days > 0) + ::sprintf(buffer, "%dd%dh%dm", days, hours, minutes); + else if (hours > 0) + ::sprintf(buffer, "%dh%dm", hours, minutes); + else if (minutes > 0) + ::sprintf(buffer, "%dm", minutes); + else + ::sprintf(buffer, "%ds", seconds); + return buffer; +} + +// Returns the given time is seconds in format DDd HHh MMm SSs +static std::string get_time_dhms(float time_in_secs) +{ + int days = (int)(time_in_secs / 86400.0f); + time_in_secs -= (float)days * 86400.0f; + int hours = (int)(time_in_secs / 3600.0f); + time_in_secs -= (float)hours * 3600.0f; + int minutes = (int)(time_in_secs / 60.0f); + time_in_secs -= (float)minutes * 60.0f; + + char buffer[64]; + if (days > 0) + ::sprintf(buffer, "%dd %dh %dm %ds", days, hours, minutes, (int)time_in_secs); + else if (hours > 0) + ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs); + else if (minutes > 0) + ::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs); + else + ::sprintf(buffer, "%ds", (int)time_in_secs); + + return buffer; +} + } // namespace Slic3r #if WIN32 diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 6727bb799..4fc032471 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -42,22 +42,27 @@ namespace Slic3r { static boost::log::trivial::severity_level logSeverity = boost::log::trivial::error; -void set_logging_level(unsigned int level) +static boost::log::trivial::severity_level level_to_boost(unsigned level) { switch (level) { // Report fatal errors only. - case 0: logSeverity = boost::log::trivial::fatal; break; + case 0: return boost::log::trivial::fatal; // Report fatal errors and errors. - case 1: logSeverity = boost::log::trivial::error; break; + case 1: return boost::log::trivial::error; // Report fatal errors, errors and warnings. - case 2: logSeverity = boost::log::trivial::warning; break; + case 2: return boost::log::trivial::warning; // Report all errors, warnings and infos. - case 3: logSeverity = boost::log::trivial::info; break; + case 3: return boost::log::trivial::info; // Report all errors, warnings, infos and debugging. - case 4: logSeverity = boost::log::trivial::debug; break; + case 4: return boost::log::trivial::debug; // Report everyting including fine level tracing information. - default: logSeverity = boost::log::trivial::trace; break; + default: return boost::log::trivial::trace; } +} + +void set_logging_level(unsigned int level) +{ + logSeverity = level_to_boost(level); boost::log::core::get()->set_filter ( @@ -73,6 +78,7 @@ unsigned get_logging_level() case boost::log::trivial::warning : return 2; case boost::log::trivial::info : return 3; case boost::log::trivial::debug : return 4; + case boost::log::trivial::trace : return 5; default: return 1; } } @@ -88,21 +94,7 @@ static struct RunOnInit { void trace(unsigned int level, const char *message) { - boost::log::trivial::severity_level severity = boost::log::trivial::trace; - switch (level) { - // Report fatal errors only. - case 0: severity = boost::log::trivial::fatal; break; - // Report fatal errors and errors. - case 1: severity = boost::log::trivial::error; break; - // Report fatal errors, errors and warnings. - case 2: severity = boost::log::trivial::warning; break; - // Report all errors, warnings and infos. - case 3: severity = boost::log::trivial::info; break; - // Report all errors, warnings, infos and debugging. - case 4: severity = boost::log::trivial::debug; break; - // Report everyting including fine level tracing information. - default: severity = boost::log::trivial::trace; break; - } + boost::log::trivial::severity_level severity = level_to_boost(level); BOOST_LOG_STREAM_WITH_PARAMS(::boost::log::trivial::logger::get(),\ (::boost::log::keywords::severity = severity)) << message; diff --git a/src/nanosvg/nanosvg.h b/src/nanosvg/nanosvg.h new file mode 100644 index 000000000..8c8b061cd --- /dev/null +++ b/src/nanosvg/nanosvg.h @@ -0,0 +1,2975 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example + * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) + * + * Arc calculation code based on canvg (https://code.google.com/p/canvg/) + * + * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * + */ + +#ifndef NANOSVG_H +#define NANOSVG_H + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. +// +// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. +// +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! +// +// The shapes in the SVG images are transformed by the viewBox and converted to specified units. +// That is, you should get the same looking data as your designed in your favorite app. +// +// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose +// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. +// +// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. +// DPI (dots-per-inch) controls how the unit conversion is done. +// +// If you don't know or care about the units stuff, "px" and 96 should get you going. + + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); +*/ + +enum NSVGpaintType { + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 +}; + +enum NSVGspreadType { + NSVG_SPREAD_PAD = 0, + NSVG_SPREAD_REFLECT = 1, + NSVG_SPREAD_REPEAT = 2 +}; + +enum NSVGlineJoin { + NSVG_JOIN_MITER = 0, + NSVG_JOIN_ROUND = 1, + NSVG_JOIN_BEVEL = 2 +}; + +enum NSVGlineCap { + NSVG_CAP_BUTT = 0, + NSVG_CAP_ROUND = 1, + NSVG_CAP_SQUARE = 2 +}; + +enum NSVGfillRule { + NSVG_FILLRULE_NONZERO = 0, + NSVG_FILLRULE_EVENODD = 1 +}; + +enum NSVGflags { + NSVG_FLAGS_VISIBLE = 0x01 +}; + +typedef struct NSVGgradientStop { + unsigned int color; + float offset; +} NSVGgradientStop; + +typedef struct NSVGgradient { + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; +} NSVGgradient; + +typedef struct NSVGpaint { + char type; + union { + unsigned int color; + NSVGgradient* gradient; + }; +} NSVGpaint; + +typedef struct NSVGpath +{ + float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath* next; // Pointer to next path, or NULL if last element. +} NSVGpath; + +typedef struct NSVGshape +{ + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath* paths; // Linked list of paths in the image. + struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +} NSVGshape; + +typedef struct NSVGimage +{ + float width; // Width of the image. + float height; // Height of the image. + NSVGshape* shapes; // Linked list of shapes in the image. +} NSVGimage; + +// Parses SVG file from a file, returns SVG image as paths. +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); + +// Parses SVG file from a null terminated string, returns SVG image as paths. +// Important note: changes the string. +NSVGimage* nsvgParse(char* input, const char* units, float dpi); + +// Duplicates a path. +NSVGpath* nsvgDuplicatePath(NSVGpath* p); + +// Deletes an image. +void nsvgDelete(NSVGimage* image); + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#endif // NANOSVG_H + +#ifdef NANOSVG_IMPLEMENTATION + +#include +#include +#include + +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. + +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_SLICE 2 + +#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + +#ifdef _MSC_VER + #pragma warning (disable: 4996) // Switch off security warnings + #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings + #ifdef __cplusplus + #define NSVG_INLINE inline + #else + #define NSVG_INLINE + #endif +#else + #define NSVG_INLINE inline +#endif + + +static int nsvg__isspace(char c) +{ + return strchr(" \t\n\v\f\r", c) != 0; +} + +static int nsvg__isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int nsvg__isnum(char c) +{ + return strchr("0123456789+-.eE", c) != 0; +} + +static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } +static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } + + +// Simple XML parser + +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 +#define NSVG_XML_MAX_ATTRIBS 256 + +static void nsvg__parseContent(char* s, + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + // Trim start white spaces + while (*s && nsvg__isspace(*s)) s++; + if (!*s) return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char* s, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void* ud) +{ + const char* attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char* name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) s++; + if (*s) { *s++ = '\0'; } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { + char* name = NULL; + char* value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) s++; + if (!*s) break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') s++; + if (*s) { *s++ = '\0'; } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') s++; + if (!*s) break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) s++; + if (*s) { *s++ = '\0'; } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char* input, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + char* s = input; + char* mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; +} + + +/* Simple SVG parser. */ + +#define NSVG_MAX_ATTR 128 + +enum NSVGgradientUnits { + NSVG_USER_SPACE = 0, + NSVG_OBJECT_SPACE = 1 +}; + +#define NSVG_MAX_DASHES 8 + +enum NSVGunits { + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX +}; + +typedef struct NSVGcoordinate { + float value; + int units; +} NSVGcoordinate; + +typedef struct NSVGlinearData { + NSVGcoordinate x1, y1, x2, y2; +} NSVGlinearData; + +typedef struct NSVGradialData { + NSVGcoordinate cx, cy, r, fx, fy; +} NSVGradialData; + +typedef struct NSVGgradientData +{ + char id[64]; + char ref[64]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop* stops; + struct NSVGgradientData* next; +} NSVGgradientData; + +typedef struct NSVGattrib +{ + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; +} NSVGattrib; + +typedef struct NSVGparser +{ + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float* pts; + int npts; + int cpts; + NSVGpath* plist; + NSVGimage* image; + NSVGgradientData* gradients; + NSVGshape* shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; +} NSVGparser; + +static void nsvg__xformIdentity(float* t) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float* t, float tx, float ty) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = tx; t[5] = ty; +} + +static void nsvg__xformSetScale(float* t, float sx, float sy) +{ + t[0] = sx; t[1] = 0.0f; + t[2] = 0.0f; t[3] = sy; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float* t, float a) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = tanf(a); t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float* t, float a) +{ + t[0] = 1.0f; t[1] = tanf(a); + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float* t, float a) +{ + float cs = cosf(a), sn = sinf(a); + t[0] = cs; t[1] = sn; + t[2] = -sn; t[3] = cs; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float* t, float* s) +{ + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float* inv, float* t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float* t, float* s) +{ + float s2[6]; + memcpy(s2, s, sizeof(float)*6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float)*6); +} + +static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2] + t[4]; + *dy = x*t[1] + y*t[3] + t[5]; +} + +static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2]; + *dy = x*t[1] + y*t[3]; +} + +#define NSVG_EPSILON (1e-12) + +static int nsvg__ptInBounds(float* pt, float* bounds) +{ + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) +{ + double it = 1.0-t; + return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; +} + +static void nsvg__curveBounds(float* bounds, float* curve) +{ + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float* v0 = &curve[0]; + float* v1 = &curve[2]; + float* v2 = &curve[4]; + float* v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b*b - 4.0*c*a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); + bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); + } + } +} + +static NSVGparser* nsvg__createParser() +{ + NSVGparser* p; + p = (NSVGparser*)malloc(sizeof(NSVGparser)); + if (p == NULL) goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); + if (p->image == NULL) goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0,0,0); + p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; + +error: + if (p) { + if (p->image) free(p->image); + free(p); + } + return NULL; +} + +static void nsvg__deletePaths(NSVGpath* path) +{ + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } +} + +static void nsvg__deletePaint(NSVGpaint* paint) +{ + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); +} + +static void nsvg__deleteGradientData(NSVGgradientData* grad) +{ + NSVGgradientData* next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser* p) +{ + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser* p) +{ + p->npts = 0; +} + +static void nsvg__addPoint(NSVGparser* p, float x, float y) +{ + if (p->npts+1 > p->cpts) { + p->cpts = p->cpts ? p->cpts*2 : 8; + p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); + if (!p->pts) return; + } + p->pts[p->npts*2+0] = x; + p->pts[p->npts*2+1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser* p, float x, float y) +{ + if (p->npts > 0) { + p->pts[(p->npts-1)*2+0] = x; + p->pts[(p->npts-1)*2+1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser* p, float x, float y) +{ + float px,py, dx,dy; + if (p->npts > 0) { + px = p->pts[(p->npts-1)*2+0]; + py = p->pts[(p->npts-1)*2+1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); + nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +{ + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); +} + +static NSVGattrib* nsvg__getAttr(NSVGparser* p) +{ + return &p->attr[p->attrHead]; +} + +static void nsvg__pushAttr(NSVGparser* p) +{ + if (p->attrHead < NSVG_MAX_ATTR-1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser* p) +{ + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser* p) +{ + return p->viewMinx; +} + +static float nsvg__actualOrigY(NSVGparser* p) +{ + return p->viewMiny; +} + +static float nsvg__actualWidth(NSVGparser* p) +{ + return p->viewWidth; +} + +static float nsvg__actualHeight(NSVGparser* p) +{ + return p->viewHeight; +} + +static float nsvg__actualLength(NSVGparser* p) +{ + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w*w + h*h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) +{ + NSVGattrib* attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: return c.value; + case NSVG_UNITS_PX: return c.value; + case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: return c.value * p->dpi; + case NSVG_UNITS_EM: return c.value * attr->fontSize; + case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; + default: return c.value; + } + return c.value; +} + +static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) +{ + NSVGgradientData* grad = p->gradients; + while (grad) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGgradientData* data = NULL; + NSVGgradientData* ref = NULL; + NSVGgradientStop* stops = NULL; + NSVGgradient* grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + + data = nsvg__findGradientData(p, id); + if (data == NULL) return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + while (ref != NULL) { + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + ref = nsvg__findGradientData(p, ref->ref); + } + if (stops == NULL) return NULL; + + grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); + if (grad == NULL) return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; grad->xform[1] = -dx; + grad->xform[2] = dx; grad->xform[3] = dy; + grad->xform[4] = x1; grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; grad->xform[1] = 0; + grad->xform[2] = 0; grad->xform[3] = r; + grad->xform[4] = cx; grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float* t) +{ + float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); + float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) +{ + NSVGpath* path; + float curve[4*2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts-1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser* p) +{ + NSVGattrib* attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape* shape; + NSVGpath* path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape*)malloc(sizeof(NSVGshape)); + if (shape == NULL) goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; + } else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; + } else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; + +error: + if (shape) free(shape); +} + +static void nsvg__addPath(NSVGparser* p, char closed) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGpath* path = NULL; + float bounds[4]; + float* curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + path = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (path == NULL) goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (path->pts == NULL) goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts-1; i += 3) { + curve = &path->pts[i*2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; + +error: + if (path != NULL) { + if (path->pts != NULL) free(path->pts); + free(path); + } +} + +// We roll our own string to float because the std library one uses locale and messes things up. +static double nsvg__atof(const char* s) +{ + char* cur = (char*)s; + char* end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = (double)strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + int expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + + +static const char* nsvg__parseNumber(const char* s, char* it, const int size) +{ + const int last = size-1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + // exponent + if (*s == 'e' || *s == 'E') { + if (i < last) it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char* nsvg__getNextPathItem(const char* s, char* it) +{ + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char* str) +{ + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while(str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } else if (n == 3) { + sscanf(str, "%x", &c); + c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); + c |= c<<4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r,g,b); +} + +static unsigned int nsvg__parseColorRGB(const char* str) +{ + int r = -1, g = -1, b = -1; + char s1[32]="", s2[32]=""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); + } else { + return NSVG_RGB(r,g,b); + } +} + +typedef struct NSVGNamedColor { + const char* name; + unsigned int color; +} NSVGNamedColor; + +NSVGNamedColor nsvg__colors[] = { + + { "red", NSVG_RGB(255, 0, 0) }, + { "green", NSVG_RGB( 0, 128, 0) }, + { "blue", NSVG_RGB( 0, 0, 255) }, + { "yellow", NSVG_RGB(255, 255, 0) }, + { "cyan", NSVG_RGB( 0, 255, 255) }, + { "magenta", NSVG_RGB(255, 0, 255) }, + { "black", NSVG_RGB( 0, 0, 0) }, + { "grey", NSVG_RGB(128, 128, 128) }, + { "gray", NSVG_RGB(128, 128, 128) }, + { "white", NSVG_RGB(255, 255, 255) }, + +#ifdef NANOSVG_ALL_COLOR_KEYWORDS + { "aliceblue", NSVG_RGB(240, 248, 255) }, + { "antiquewhite", NSVG_RGB(250, 235, 215) }, + { "aqua", NSVG_RGB( 0, 255, 255) }, + { "aquamarine", NSVG_RGB(127, 255, 212) }, + { "azure", NSVG_RGB(240, 255, 255) }, + { "beige", NSVG_RGB(245, 245, 220) }, + { "bisque", NSVG_RGB(255, 228, 196) }, + { "blanchedalmond", NSVG_RGB(255, 235, 205) }, + { "blueviolet", NSVG_RGB(138, 43, 226) }, + { "brown", NSVG_RGB(165, 42, 42) }, + { "burlywood", NSVG_RGB(222, 184, 135) }, + { "cadetblue", NSVG_RGB( 95, 158, 160) }, + { "chartreuse", NSVG_RGB(127, 255, 0) }, + { "chocolate", NSVG_RGB(210, 105, 30) }, + { "coral", NSVG_RGB(255, 127, 80) }, + { "cornflowerblue", NSVG_RGB(100, 149, 237) }, + { "cornsilk", NSVG_RGB(255, 248, 220) }, + { "crimson", NSVG_RGB(220, 20, 60) }, + { "darkblue", NSVG_RGB( 0, 0, 139) }, + { "darkcyan", NSVG_RGB( 0, 139, 139) }, + { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, + { "darkgray", NSVG_RGB(169, 169, 169) }, + { "darkgreen", NSVG_RGB( 0, 100, 0) }, + { "darkgrey", NSVG_RGB(169, 169, 169) }, + { "darkkhaki", NSVG_RGB(189, 183, 107) }, + { "darkmagenta", NSVG_RGB(139, 0, 139) }, + { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, + { "darkorange", NSVG_RGB(255, 140, 0) }, + { "darkorchid", NSVG_RGB(153, 50, 204) }, + { "darkred", NSVG_RGB(139, 0, 0) }, + { "darksalmon", NSVG_RGB(233, 150, 122) }, + { "darkseagreen", NSVG_RGB(143, 188, 143) }, + { "darkslateblue", NSVG_RGB( 72, 61, 139) }, + { "darkslategray", NSVG_RGB( 47, 79, 79) }, + { "darkslategrey", NSVG_RGB( 47, 79, 79) }, + { "darkturquoise", NSVG_RGB( 0, 206, 209) }, + { "darkviolet", NSVG_RGB(148, 0, 211) }, + { "deeppink", NSVG_RGB(255, 20, 147) }, + { "deepskyblue", NSVG_RGB( 0, 191, 255) }, + { "dimgray", NSVG_RGB(105, 105, 105) }, + { "dimgrey", NSVG_RGB(105, 105, 105) }, + { "dodgerblue", NSVG_RGB( 30, 144, 255) }, + { "firebrick", NSVG_RGB(178, 34, 34) }, + { "floralwhite", NSVG_RGB(255, 250, 240) }, + { "forestgreen", NSVG_RGB( 34, 139, 34) }, + { "fuchsia", NSVG_RGB(255, 0, 255) }, + { "gainsboro", NSVG_RGB(220, 220, 220) }, + { "ghostwhite", NSVG_RGB(248, 248, 255) }, + { "gold", NSVG_RGB(255, 215, 0) }, + { "goldenrod", NSVG_RGB(218, 165, 32) }, + { "greenyellow", NSVG_RGB(173, 255, 47) }, + { "honeydew", NSVG_RGB(240, 255, 240) }, + { "hotpink", NSVG_RGB(255, 105, 180) }, + { "indianred", NSVG_RGB(205, 92, 92) }, + { "indigo", NSVG_RGB( 75, 0, 130) }, + { "ivory", NSVG_RGB(255, 255, 240) }, + { "khaki", NSVG_RGB(240, 230, 140) }, + { "lavender", NSVG_RGB(230, 230, 250) }, + { "lavenderblush", NSVG_RGB(255, 240, 245) }, + { "lawngreen", NSVG_RGB(124, 252, 0) }, + { "lemonchiffon", NSVG_RGB(255, 250, 205) }, + { "lightblue", NSVG_RGB(173, 216, 230) }, + { "lightcoral", NSVG_RGB(240, 128, 128) }, + { "lightcyan", NSVG_RGB(224, 255, 255) }, + { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, + { "lightgray", NSVG_RGB(211, 211, 211) }, + { "lightgreen", NSVG_RGB(144, 238, 144) }, + { "lightgrey", NSVG_RGB(211, 211, 211) }, + { "lightpink", NSVG_RGB(255, 182, 193) }, + { "lightsalmon", NSVG_RGB(255, 160, 122) }, + { "lightseagreen", NSVG_RGB( 32, 178, 170) }, + { "lightskyblue", NSVG_RGB(135, 206, 250) }, + { "lightslategray", NSVG_RGB(119, 136, 153) }, + { "lightslategrey", NSVG_RGB(119, 136, 153) }, + { "lightsteelblue", NSVG_RGB(176, 196, 222) }, + { "lightyellow", NSVG_RGB(255, 255, 224) }, + { "lime", NSVG_RGB( 0, 255, 0) }, + { "limegreen", NSVG_RGB( 50, 205, 50) }, + { "linen", NSVG_RGB(250, 240, 230) }, + { "maroon", NSVG_RGB(128, 0, 0) }, + { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, + { "mediumblue", NSVG_RGB( 0, 0, 205) }, + { "mediumorchid", NSVG_RGB(186, 85, 211) }, + { "mediumpurple", NSVG_RGB(147, 112, 219) }, + { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, + { "mediumslateblue", NSVG_RGB(123, 104, 238) }, + { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, + { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, + { "mediumvioletred", NSVG_RGB(199, 21, 133) }, + { "midnightblue", NSVG_RGB( 25, 25, 112) }, + { "mintcream", NSVG_RGB(245, 255, 250) }, + { "mistyrose", NSVG_RGB(255, 228, 225) }, + { "moccasin", NSVG_RGB(255, 228, 181) }, + { "navajowhite", NSVG_RGB(255, 222, 173) }, + { "navy", NSVG_RGB( 0, 0, 128) }, + { "oldlace", NSVG_RGB(253, 245, 230) }, + { "olive", NSVG_RGB(128, 128, 0) }, + { "olivedrab", NSVG_RGB(107, 142, 35) }, + { "orange", NSVG_RGB(255, 165, 0) }, + { "orangered", NSVG_RGB(255, 69, 0) }, + { "orchid", NSVG_RGB(218, 112, 214) }, + { "palegoldenrod", NSVG_RGB(238, 232, 170) }, + { "palegreen", NSVG_RGB(152, 251, 152) }, + { "paleturquoise", NSVG_RGB(175, 238, 238) }, + { "palevioletred", NSVG_RGB(219, 112, 147) }, + { "papayawhip", NSVG_RGB(255, 239, 213) }, + { "peachpuff", NSVG_RGB(255, 218, 185) }, + { "peru", NSVG_RGB(205, 133, 63) }, + { "pink", NSVG_RGB(255, 192, 203) }, + { "plum", NSVG_RGB(221, 160, 221) }, + { "powderblue", NSVG_RGB(176, 224, 230) }, + { "purple", NSVG_RGB(128, 0, 128) }, + { "rosybrown", NSVG_RGB(188, 143, 143) }, + { "royalblue", NSVG_RGB( 65, 105, 225) }, + { "saddlebrown", NSVG_RGB(139, 69, 19) }, + { "salmon", NSVG_RGB(250, 128, 114) }, + { "sandybrown", NSVG_RGB(244, 164, 96) }, + { "seagreen", NSVG_RGB( 46, 139, 87) }, + { "seashell", NSVG_RGB(255, 245, 238) }, + { "sienna", NSVG_RGB(160, 82, 45) }, + { "silver", NSVG_RGB(192, 192, 192) }, + { "skyblue", NSVG_RGB(135, 206, 235) }, + { "slateblue", NSVG_RGB(106, 90, 205) }, + { "slategray", NSVG_RGB(112, 128, 144) }, + { "slategrey", NSVG_RGB(112, 128, 144) }, + { "snow", NSVG_RGB(255, 250, 250) }, + { "springgreen", NSVG_RGB( 0, 255, 127) }, + { "steelblue", NSVG_RGB( 70, 130, 180) }, + { "tan", NSVG_RGB(210, 180, 140) }, + { "teal", NSVG_RGB( 0, 128, 128) }, + { "thistle", NSVG_RGB(216, 191, 216) }, + { "tomato", NSVG_RGB(255, 99, 71) }, + { "turquoise", NSVG_RGB( 64, 224, 208) }, + { "violet", NSVG_RGB(238, 130, 238) }, + { "wheat", NSVG_RGB(245, 222, 179) }, + { "whitesmoke", NSVG_RGB(245, 245, 245) }, + { "yellowgreen", NSVG_RGB(154, 205, 50) }, +#endif +}; + +static unsigned int nsvg__parseColorName(const char* str) +{ + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char* str) +{ + size_t len = 0; + while(*str == ' ') ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + if (val > 1.0f) val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char* units) +{ + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) +{ + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) +{ + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) +{ + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) +{ + const char* end; + const char* ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + + +static int nsvg__parseMatrix(float* xform, const char* str) +{ + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) return len; + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseTranslate(float* xform, const char* str) +{ + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseScale(float* xform, const char* str) +{ + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewX(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewY(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseRotate(float* xform, const char* str) +{ + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float)*6); + + return len; +} + +static void nsvg__parseTransform(float* xform, const char* str) +{ + float t[6]; + nsvg__xformIdentity(xform); + while (*str) + { + if (strncmp(str, "matrix", 6) == 0) + str += nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + str += nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + str += nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + str += nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + str += nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + str += nsvg__parseSkewY(t, str); + else{ + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char* id, const char* str) +{ + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < 63 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char* str) +{ + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char* str) +{ + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char* str) +{ + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char* nsvg__getNextDashItem(const char* s, char* it) +{ + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) +{ + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str); + +static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) +{ + float xform[6]; + NSVGattrib* attr = nsvg__getAttr(p); + if (!attr) return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) +{ + const char* str; + const char* val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; + ++str; + + n = (int)(str - start); + if (n > 511) n = 511; + if (n) memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + + n = (int)(end - val); + if (n > 511) n = 511; + if (n) memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str) +{ + const char* start; + const char* end; + + while (*str) { + // Left Trim + while(*str && nsvg__isspace(*str)) ++str; + start = str; + while(*str && *str != ';') ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) + { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) +{ + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + } + return 0; +} + +static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2*x1 - *cpx2; + cy1 = 2*y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2*x1 - *cpx2; + cy = 2*y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x*x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) +{ + return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) +{ + float r = nsvg__vecrat(ux,uy, vx,vy); + if (r < -1.0f) r = -1.0f; + if (r > 1.0f) r = 1.0f; + return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx*dx + dy*dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); + sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); + if (sa < 0.0f) sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; + cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle + da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + +// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; +// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; t[1] = sinrx; + t[2] = -sinrx; t[3] = cosrx; + t[4] = cx; t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i/(float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser* p, const char** attr) +{ + const char* s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + float cpx, cpy, cpx2, cpy2; + const char* tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; cpy = 0; + cpx2 = 0; cpy2 = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + s = nsvg__getNextPathItem(s, item); + if (!*item) break; + if (nsvg__isnum(item[0])) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; cpy2 = cpy; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs-2]; + cpy = args[nargs-1]; + cpx2 = cpx; cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + cmd = item[0]; + rargs = nsvg__getArgsPerElement(cmd); + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser* p, const char** attr) +{ + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) rx = ry; + if (ry < 0.0f && rx > 0.0f) ry = rx; + if (rx < 0.0f) rx = 0.0f; + if (ry < 0.0f) ry = 0.0f; + if (rx > w/2.0f) rx = w/2.0f; + if (ry > h/2.0f) ry = h/2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x+w, y); + nsvg__lineTo(p, x+w, y+h); + nsvg__lineTo(p, x, y+h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x+rx, y); + nsvg__lineTo(p, x+w-rx, y); + nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); + nsvg__lineTo(p, x+w, y+h-ry); + nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); + nsvg__lineTo(p, x+rx, y+h); + nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); + nsvg__lineTo(p, x, y+ry); + nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+r, cy); + nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); + nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); + nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); + nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+rx, cy); + nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); + nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); + nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); + nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser* p, const char** attr) +{ + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) +{ + int i; + const char* s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) +{ + int i; + NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i+1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i+1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i+1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i+1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i+1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i+1]; + strncpy(grad->ref, href+1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) +{ + NSVGattrib* curAttr = nsvg__getAttr(p); + NSVGgradientData* grad; + NSVGgradientStop* stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) return; + + grad->nstops++; + grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); + if (grad->stops == NULL) return; + + // Insert + idx = grad->nstops-1; + for (i = 0; i < grad->nstops-1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops-1) { + for (i = grad->nstops-1; i > idx; i--) + grad->stops[i] = grad->stops[i-1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void* ud, const char* el, const char** attr) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void* ud, const char* el) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void* ud, const char* s) +{ + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser* p, float* bounds) +{ + NSVGshape* shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) +{ + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) +{ + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply (grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply (grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) +{ + NSVGshape* shape; + NSVGpath* path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float* pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx+sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i =0; i < path->npts; i++) { + pt = &path->pts[i*2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +NSVGimage* nsvgParse(char* input, const char* units, float dpi) +{ + NSVGparser* p; + NSVGimage* ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) +{ + FILE* fp = NULL; + size_t size; + char* data = NULL; + NSVGimage* image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char*)malloc(size+1); + if (data == NULL) goto error; + if (fread(data, 1, size, fp) != size) goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; + +error: + if (fp) fclose(fp); + if (data) free(data); + if (image) nsvgDelete(image); + return NULL; +} + +NSVGpath* nsvgDuplicatePath(NSVGpath* p) +{ + NSVGpath* res = NULL; + + if (p == NULL) + return NULL; + + res = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (res == NULL) goto error; + memset(res, 0, sizeof(NSVGpath)); + + res->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (res->pts == NULL) goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; + + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + + res->closed = p->closed; + + return res; + +error: + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; +} + +void nsvgDelete(NSVGimage* image) +{ + NSVGshape *snext, *shape; + if (image == NULL) return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); +} + +#endif diff --git a/src/nanosvg/nanosvgrast.h b/src/nanosvg/nanosvgrast.h new file mode 100644 index 000000000..b740c316c --- /dev/null +++ b/src/nanosvg/nanosvgrast.h @@ -0,0 +1,1452 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The polygon rasterization is heavily based on stb_truetype rasterizer + * by Sean Barrett - http://nothings.org/ + * + */ + +#ifndef NANOSVGRAST_H +#define NANOSVGRAST_H + +#ifndef NANOSVGRAST_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +typedef struct NSVGrasterizer NSVGrasterizer; + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + + // Create rasterizer (can be used to render multiple images). + struct NSVGrasterizer* rast = nsvgCreateRasterizer(); + // Allocate memory for image + unsigned char* img = malloc(w*h*4); + // Rasterize + nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4); +*/ + +// Allocated rasterizer context. +NSVGrasterizer* nsvgCreateRasterizer(); + +// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) +// r - pointer to rasterizer context +// image - pointer to image to rasterize +// tx,ty - image offset (applied after scaling) +// scale - image scale +// dst - pointer to destination image data, 4 bytes per pixel (RGBA) +// w - width of the image to render +// h - height of the image to render +// stride - number of bytes per scaleline in the destination buffer +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride); + +// Deletes rasterizer context. +void nsvgDeleteRasterizer(NSVGrasterizer*); + + +#ifndef NANOSVGRAST_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#endif // NANOSVGRAST_H + +#ifdef NANOSVGRAST_IMPLEMENTATION + +#include + +#define NSVG__SUBSAMPLES 5 +#define NSVG__FIXSHIFT 10 +#define NSVG__FIX (1 << NSVG__FIXSHIFT) +#define NSVG__FIXMASK (NSVG__FIX-1) +#define NSVG__MEMPAGE_SIZE 1024 + +typedef struct NSVGedge { + float x0,y0, x1,y1; + int dir; + struct NSVGedge* next; +} NSVGedge; + +typedef struct NSVGpoint { + float x, y; + float dx, dy; + float len; + float dmx, dmy; + unsigned char flags; +} NSVGpoint; + +typedef struct NSVGactiveEdge { + int x,dx; + float ey; + int dir; + struct NSVGactiveEdge *next; +} NSVGactiveEdge; + +typedef struct NSVGmemPage { + unsigned char mem[NSVG__MEMPAGE_SIZE]; + int size; + struct NSVGmemPage* next; +} NSVGmemPage; + +typedef struct NSVGcachedPaint { + char type; + char spread; + float xform[6]; + unsigned int colors[256]; +} NSVGcachedPaint; + +struct NSVGrasterizer +{ + float px, py; + + float tessTol; + float distTol; + + NSVGedge* edges; + int nedges; + int cedges; + + NSVGpoint* points; + int npoints; + int cpoints; + + NSVGpoint* points2; + int npoints2; + int cpoints2; + + NSVGactiveEdge* freelist; + NSVGmemPage* pages; + NSVGmemPage* curpage; + + unsigned char* scanline; + int cscanline; + + unsigned char* bitmap; + int width, height, stride; +}; + +NSVGrasterizer* nsvgCreateRasterizer() +{ + NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); + if (r == NULL) goto error; + memset(r, 0, sizeof(NSVGrasterizer)); + + r->tessTol = 0.25f; + r->distTol = 0.01f; + + return r; + +error: + nsvgDeleteRasterizer(r); + return NULL; +} + +void nsvgDeleteRasterizer(NSVGrasterizer* r) +{ + NSVGmemPage* p; + + if (r == NULL) return; + + p = r->pages; + while (p != NULL) { + NSVGmemPage* next = p->next; + free(p); + p = next; + } + + if (r->edges) free(r->edges); + if (r->points) free(r->points); + if (r->points2) free(r->points2); + if (r->scanline) free(r->scanline); + + free(r); +} + +static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) +{ + NSVGmemPage *newp; + + // If using existing chain, return the next page in chain + if (cur != NULL && cur->next != NULL) { + return cur->next; + } + + // Alloc new page + newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage)); + if (newp == NULL) return NULL; + memset(newp, 0, sizeof(NSVGmemPage)); + + // Add to linked list + if (cur != NULL) + cur->next = newp; + else + r->pages = newp; + + return newp; +} + +static void nsvg__resetPool(NSVGrasterizer* r) +{ + NSVGmemPage* p = r->pages; + while (p != NULL) { + p->size = 0; + p = p->next; + } + r->curpage = r->pages; +} + +static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) +{ + unsigned char* buf; + if (size > NSVG__MEMPAGE_SIZE) return NULL; + if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { + r->curpage = nsvg__nextPage(r, r->curpage); + } + buf = &r->curpage->mem[r->curpage->size]; + r->curpage->size += size; + return buf; +} + +static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) +{ + float dx = x2 - x1; + float dy = y2 - y1; + return dx*dx + dy*dy < tol*tol; +} + +static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) +{ + NSVGpoint* pt; + + if (r->npoints > 0) { + pt = &r->points[r->npoints-1]; + if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { + pt->flags = (unsigned char)(pt->flags | flags); + return; + } + } + + if (r->npoints+1 > r->cpoints) { + r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; + r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) return; + } + + pt = &r->points[r->npoints]; + pt->x = x; + pt->y = y; + pt->flags = (unsigned char)flags; + r->npoints++; +} + +static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) +{ + if (r->npoints+1 > r->cpoints) { + r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; + r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) return; + } + r->points[r->npoints] = pt; + r->npoints++; +} + +static void nsvg__duplicatePoints(NSVGrasterizer* r) +{ + if (r->npoints > r->cpoints2) { + r->cpoints2 = r->npoints; + r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); + if (r->points2 == NULL) return; + } + + memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); + r->npoints2 = r->npoints; +} + +static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) +{ + NSVGedge* e; + + // Skip horizontal edges + if (y0 == y1) + return; + + if (r->nedges+1 > r->cedges) { + r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; + r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges); + if (r->edges == NULL) return; + } + + e = &r->edges[r->nedges]; + r->nedges++; + + if (y0 < y1) { + e->x0 = x0; + e->y0 = y0; + e->x1 = x1; + e->y1 = y1; + e->dir = 1; + } else { + e->x0 = x1; + e->y0 = y1; + e->x1 = x0; + e->y1 = y0; + e->dir = -1; + } +} + +static float nsvg__normalize(float *x, float* y) +{ + float d = sqrtf((*x)*(*x) + (*y)*(*y)); + if (d > 1e-6f) { + float id = 1.0f / d; + *x *= id; + *y *= id; + } + return d; +} + +static float nsvg__absf(float x) { return x < 0 ? -x : x; } + +static void nsvg__flattenCubicBez(NSVGrasterizer* r, + float x1, float y1, float x2, float y2, + float x3, float y3, float x4, float y4, + int level, int type) +{ + float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; + float dx,dy,d2,d3; + + if (level > 10) return; + + x12 = (x1+x2)*0.5f; + y12 = (y1+y2)*0.5f; + x23 = (x2+x3)*0.5f; + y23 = (y2+y3)*0.5f; + x34 = (x3+x4)*0.5f; + y34 = (y3+y4)*0.5f; + x123 = (x12+x23)*0.5f; + y123 = (y12+y23)*0.5f; + + dx = x4 - x1; + dy = y4 - y1; + d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); + d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); + + if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { + nsvg__addPathPoint(r, x4, y4, type); + return; + } + + x234 = (x23+x34)*0.5f; + y234 = (y23+y34)*0.5f; + x1234 = (x123+x234)*0.5f; + y1234 = (y123+y234)*0.5f; + + nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); + nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); +} + +static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) +{ + int i, j; + NSVGpath* path; + + for (path = shape->paths; path != NULL; path = path->next) { + r->npoints = 0; + // Flatten path + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + for (i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); + } + // Close path + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + // Build edges + for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) + nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); + } +} + +enum NSVGpointFlags +{ + NSVG_PT_CORNER = 0x01, + NSVG_PT_BEVEL = 0x02, + NSVG_PT_LEFT = 0x04 +}; + +static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + float len = nsvg__normalize(&dx, &dy); + float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +{ + float w = lineWidth * 0.5f; + float px = p->x, py = p->y; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + + nsvg__addEdge(r, lx, ly, rx, ry); + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +{ + float w = lineWidth * 0.5f; + float px = p->x - dx*w, py = p->y - dy*w; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + + nsvg__addEdge(r, lx, ly, rx, ry); + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +#ifndef NSVG_PI +#define NSVG_PI (3.14159265358979323846264338327f) +#endif + +static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) +{ + int i; + float w = lineWidth * 0.5f; + float px = p->x, py = p->y; + float dlx = dy, dly = -dx; + float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; + + for (i = 0; i < ncap; i++) { + float a = (float)i/(float)(ncap-1)*NSVG_PI; + float ax = cosf(a) * w, ay = sinf(a) * w; + float x = px - dlx*ax - dx*ay; + float y = py - dly*ax - dy*ay; + + if (i > 0) + nsvg__addEdge(r, prevx, prevy, x, y); + + prevx = x; + prevy = y; + + if (i == 0) { + lx = x; ly = y; + } else if (i == ncap-1) { + rx = x; ry = y; + } + } + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w); + float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w); + float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w); + float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w); + + nsvg__addEdge(r, lx0, ly0, left->x, left->y); + nsvg__addEdge(r, lx1, ly1, lx0, ly0); + + nsvg__addEdge(r, right->x, right->y, rx0, ry0); + nsvg__addEdge(r, rx0, ry0, rx1, ry1); + + left->x = lx1; left->y = ly1; + right->x = rx1; right->y = ry1; +} + +static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float lx0, rx0, lx1, rx1; + float ly0, ry0, ly1, ry1; + + if (p1->flags & NSVG_PT_LEFT) { + lx0 = lx1 = p1->x - p1->dmx * w; + ly0 = ly1 = p1->y - p1->dmy * w; + nsvg__addEdge(r, lx1, ly1, left->x, left->y); + + rx0 = p1->x + (dlx0 * w); + ry0 = p1->y + (dly0 * w); + rx1 = p1->x + (dlx1 * w); + ry1 = p1->y + (dly1 * w); + nsvg__addEdge(r, right->x, right->y, rx0, ry0); + nsvg__addEdge(r, rx0, ry0, rx1, ry1); + } else { + lx0 = p1->x - (dlx0 * w); + ly0 = p1->y - (dly0 * w); + lx1 = p1->x - (dlx1 * w); + ly1 = p1->y - (dly1 * w); + nsvg__addEdge(r, lx0, ly0, left->x, left->y); + nsvg__addEdge(r, lx1, ly1, lx0, ly0); + + rx0 = rx1 = p1->x + p1->dmx * w; + ry0 = ry1 = p1->y + p1->dmy * w; + nsvg__addEdge(r, right->x, right->y, rx1, ry1); + } + + left->x = lx1; left->y = ly1; + right->x = rx1; right->y = ry1; +} + +static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) +{ + int i, n; + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float a0 = atan2f(dly0, dlx0); + float a1 = atan2f(dly1, dlx1); + float da = a1 - a0; + float lx, ly, rx, ry; + + if (da < NSVG_PI) da += NSVG_PI*2; + if (da > NSVG_PI) da -= NSVG_PI*2; + + n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap); + if (n < 2) n = 2; + if (n > ncap) n = ncap; + + lx = left->x; + ly = left->y; + rx = right->x; + ry = right->y; + + for (i = 0; i < n; i++) { + float u = (float)i/(float)(n-1); + float a = a0 + u*da; + float ax = cosf(a) * w, ay = sinf(a) * w; + float lx1 = p1->x - ax, ly1 = p1->y - ay; + float rx1 = p1->x + ax, ry1 = p1->y + ay; + + nsvg__addEdge(r, lx1, ly1, lx, ly); + nsvg__addEdge(r, rx, ry, rx1, ry1); + + lx = lx1; ly = ly1; + rx = rx1; ry = ry1; + } + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); + float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w); + + nsvg__addEdge(r, lx, ly, left->x, left->y); + nsvg__addEdge(r, right->x, right->y, rx, ry); + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static int nsvg__curveDivs(float r, float arc, float tol) +{ + float da = acosf(r / (r + tol)) * 2.0f; + int divs = (int)ceilf(arc / da); + if (divs < 2) divs = 2; + return divs; +} + +static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) +{ + int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. + NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; + NSVGpoint* p0, *p1; + int j, s, e; + + // Build stroke edges + if (closed) { + // Looping + p0 = &points[npoints-1]; + p1 = &points[0]; + s = 0; + e = npoints; + } else { + // Add cap + p0 = &points[0]; + p1 = &points[1]; + s = 1; + e = npoints-1; + } + + if (closed) { + nsvg__initClosed(&left, &right, p0, p1, lineWidth); + firstLeft = left; + firstRight = right; + } else { + // Add cap + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + nsvg__normalize(&dx, &dy); + if (lineCap == NSVG_CAP_BUTT) + nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0); + else if (lineCap == NSVG_CAP_SQUARE) + nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0); + else if (lineCap == NSVG_CAP_ROUND) + nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0); + } + + for (j = s; j < e; ++j) { + if (p1->flags & NSVG_PT_CORNER) { + if (lineJoin == NSVG_JOIN_ROUND) + nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap); + else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL)) + nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth); + else + nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth); + } else { + nsvg__straightJoin(r, &left, &right, p1, lineWidth); + } + p0 = p1++; + } + + if (closed) { + // Loop it + nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y); + nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y); + } else { + // Add cap + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + nsvg__normalize(&dx, &dy); + if (lineCap == NSVG_CAP_BUTT) + nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); + else if (lineCap == NSVG_CAP_SQUARE) + nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); + else if (lineCap == NSVG_CAP_ROUND) + nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1); + } +} + +static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) +{ + int i, j; + NSVGpoint* p0, *p1; + + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + for (i = 0; i < r->npoints; i++) { + // Calculate segment direction and length + p0->dx = p1->x - p0->x; + p0->dy = p1->y - p0->y; + p0->len = nsvg__normalize(&p0->dx, &p0->dy); + // Advance + p0 = p1++; + } + + // calculate joins + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + for (j = 0; j < r->npoints; j++) { + float dlx0, dly0, dlx1, dly1, dmr2, cross; + dlx0 = p0->dy; + dly0 = -p0->dx; + dlx1 = p1->dy; + dly1 = -p1->dx; + // Calculate extrusions + p1->dmx = (dlx0 + dlx1) * 0.5f; + p1->dmy = (dly0 + dly1) * 0.5f; + dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; + if (dmr2 > 0.000001f) { + float s2 = 1.0f / dmr2; + if (s2 > 600.0f) { + s2 = 600.0f; + } + p1->dmx *= s2; + p1->dmy *= s2; + } + + // Clear flags, but keep the corner. + p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0; + + // Keep track of left turns. + cross = p1->dx * p0->dy - p0->dx * p1->dy; + if (cross > 0.0f) + p1->flags |= NSVG_PT_LEFT; + + // Check to see if the corner needs to be beveled. + if (p1->flags & NSVG_PT_CORNER) { + if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { + p1->flags |= NSVG_PT_BEVEL; + } + } + + p0 = p1++; + } +} + +static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) +{ + int i, j, closed; + NSVGpath* path; + NSVGpoint* p0, *p1; + float miterLimit = shape->miterLimit; + int lineJoin = shape->strokeLineJoin; + int lineCap = shape->strokeLineCap; + float lineWidth = shape->strokeWidth * scale; + + for (path = shape->paths; path != NULL; path = path->next) { + // Flatten path + r->npoints = 0; + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); + for (i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); + } + if (r->npoints < 2) + continue; + + closed = path->closed; + + // If the first and last points are the same, remove the last, mark as closed path. + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { + r->npoints--; + p0 = &r->points[r->npoints-1]; + closed = 1; + } + + if (shape->strokeDashCount > 0) { + int idash = 0, dashState = 1; + float totalDist = 0, dashLen, allDashLen, dashOffset; + NSVGpoint cur; + + if (closed) + nsvg__appendPathPoint(r, r->points[0]); + + // Duplicate points -> points2. + nsvg__duplicatePoints(r); + + r->npoints = 0; + cur = r->points2[0]; + nsvg__appendPathPoint(r, cur); + + // Figure out dash offset. + allDashLen = 0; + for (j = 0; j < shape->strokeDashCount; j++) + allDashLen += shape->strokeDashArray[j]; + if (shape->strokeDashCount & 1) + allDashLen *= 2.0f; + // Find location inside pattern + dashOffset = fmodf(shape->strokeDashOffset, allDashLen); + if (dashOffset < 0.0f) + dashOffset += allDashLen; + + while (dashOffset > shape->strokeDashArray[idash]) { + dashOffset -= shape->strokeDashArray[idash]; + idash = (idash + 1) % shape->strokeDashCount; + } + dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; + + for (j = 1; j < r->npoints2; ) { + float dx = r->points2[j].x - cur.x; + float dy = r->points2[j].y - cur.y; + float dist = sqrtf(dx*dx + dy*dy); + + if ((totalDist + dist) > dashLen) { + // Calculate intermediate point + float d = (dashLen - totalDist) / dist; + float x = cur.x + dx * d; + float y = cur.y + dy * d; + nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER); + + // Stroke + if (r->npoints > 1 && dashState) { + nsvg__prepareStroke(r, miterLimit, lineJoin); + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + } + // Advance dash pattern + dashState = !dashState; + idash = (idash+1) % shape->strokeDashCount; + dashLen = shape->strokeDashArray[idash] * scale; + // Restart + cur.x = x; + cur.y = y; + cur.flags = NSVG_PT_CORNER; + totalDist = 0.0f; + r->npoints = 0; + nsvg__appendPathPoint(r, cur); + } else { + totalDist += dist; + cur = r->points2[j]; + nsvg__appendPathPoint(r, cur); + j++; + } + } + // Stroke any leftover path + if (r->npoints > 1 && dashState) + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + } else { + nsvg__prepareStroke(r, miterLimit, lineJoin); + nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); + } + } +} + +static int nsvg__cmpEdge(const void *p, const void *q) +{ + const NSVGedge* a = (const NSVGedge*)p; + const NSVGedge* b = (const NSVGedge*)q; + + if (a->y0 < b->y0) return -1; + if (a->y0 > b->y0) return 1; + return 0; +} + + +static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) +{ + NSVGactiveEdge* z; + + if (r->freelist != NULL) { + // Restore from freelist. + z = r->freelist; + r->freelist = z->next; + } else { + // Alloc new edge. + z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); + if (z == NULL) return NULL; + } + + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); +// STBTT_assert(e->y0 <= start_point); + // round dx down to avoid going too far + if (dxdy < 0) + z->dx = (int)(-floorf(NSVG__FIX * -dxdy)); + else + z->dx = (int)floorf(NSVG__FIX * dxdy); + z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); +// z->x -= off_x * FIX; + z->ey = e->y1; + z->next = 0; + z->dir = e->dir; + + return z; +} + +static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) +{ + z->next = r->freelist; + r->freelist = z; +} + +static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) +{ + int i = x0 >> NSVG__FIXSHIFT; + int j = x1 >> NSVG__FIXSHIFT; + if (i < *xmin) *xmin = i; + if (j > *xmax) *xmax = j; + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT)); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT)); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = (unsigned char)(scanline[i] + maxWeight); + } + } +} + +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) +{ + // non-zero winding fill + int x0 = 0, w = 0; + + if (fillRule == NSVG_FILLRULE_NONZERO) { + // Non-zero + while (e != NULL) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->dir; + } else { + int x1 = e->x; w += e->dir; + // if we went to zero, we need to draw + if (w == 0) + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + } + e = e->next; + } + } else if (fillRule == NSVG_FILLRULE_EVENODD) { + // Even-odd + while (e != NULL) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w = 1; + } else { + int x1 = e->x; w = 0; + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + } + e = e->next; + } + } +} + +static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } + +static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return (r) | (g << 8) | (b << 16) | (a << 24); +} + +static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) +{ + int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; + int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; + int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; + int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; + return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); +} + +static unsigned int nsvg__applyOpacity(unsigned int c, float u) +{ + int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (c) & 0xff; + int g = (c>>8) & 0xff; + int b = (c>>16) & 0xff; + int a = (((c>>24) & 0xff)*iu) >> 8; + return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); +} + +static inline int nsvg__div255(int x) +{ + return ((x+1) * 257) >> 16; +} + +static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, + float tx, float ty, float scale, NSVGcachedPaint* cache) +{ + + if (cache->type == NSVG_PAINT_COLOR) { + int i, cr, cg, cb, ca; + cr = cache->colors[0] & 0xff; + cg = (cache->colors[0] >> 8) & 0xff; + cb = (cache->colors[0] >> 16) & 0xff; + ca = (cache->colors[0] >> 24) & 0xff; + + for (i = 0; i < count; i++) { + int r,g,b; + int a = nsvg__div255((int)cover[0] * ca); + int ia = 255 - a; + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + } + } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) { + // TODO: spread modes. + // TODO: plenty of opportunities to optimize. + float fx, fy, dx, gy; + float* t = cache->xform; + int i, cr, cg, cb, ca; + unsigned int c; + + fx = ((float)x - tx) / scale; + fy = ((float)y - ty) / scale; + dx = 1.0f / scale; + + for (i = 0; i < count; i++) { + int r,g,b,a,ia; + gy = fx*t[1] + fy*t[3] + t[5]; + c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; + cr = (c) & 0xff; + cg = (c >> 8) & 0xff; + cb = (c >> 16) & 0xff; + ca = (c >> 24) & 0xff; + + a = nsvg__div255((int)cover[0] * ca); + ia = 255 - a; + + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + fx += dx; + } + } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) { + // TODO: spread modes. + // TODO: plenty of opportunities to optimize. + // TODO: focus (fx,fy) + float fx, fy, dx, gx, gy, gd; + float* t = cache->xform; + int i, cr, cg, cb, ca; + unsigned int c; + + fx = ((float)x - tx) / scale; + fy = ((float)y - ty) / scale; + dx = 1.0f / scale; + + for (i = 0; i < count; i++) { + int r,g,b,a,ia; + gx = fx*t[0] + fy*t[2] + t[4]; + gy = fx*t[1] + fy*t[3] + t[5]; + gd = sqrtf(gx*gx + gy*gy); + c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; + cr = (c) & 0xff; + cg = (c >> 8) & 0xff; + cb = (c >> 16) & 0xff; + ca = (c >> 24) & 0xff; + + a = nsvg__div255((int)cover[0] * ca); + ia = 255 - a; + + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + fx += dx; + } + } +} + +static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) +{ + NSVGactiveEdge *active = NULL; + int y, s; + int e = 0; + int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline + int xmin, xmax; + + for (y = 0; y < r->height; y++) { + memset(r->scanline, 0, r->width); + xmin = r->width; + xmax = 0; + for (s = 0; s < NSVG__SUBSAMPLES; ++s) { + // find center of pixel for this scanline + float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f; + NSVGactiveEdge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + NSVGactiveEdge *z = *step; + if (z->ey <= scany) { + *step = z->next; // delete from list +// NSVG__assert(z->valid); + nsvg__freeActive(r, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for (;;) { + int changed = 0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + NSVGactiveEdge* t = *step; + NSVGactiveEdge* q = t->next; + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e < r->nedges && r->edges[e].y0 <= scany) { + if (r->edges[e].y1 > scany) { + NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); + if (z == NULL) break; + // find insertion point + if (active == NULL) { + active = z; + } else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + NSVGactiveEdge* p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + e++; + } + + // now process all active edges in non-zero fashion + if (active != NULL) + nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); + } + // Blit + if (xmin < 0) xmin = 0; + if (xmax > r->width-1) xmax = r->width-1; + if (xmin <= xmax) { + nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); + } + } + +} + +static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) +{ + int x,y; + + // Unpremultiply + for (y = 0; y < h; y++) { + unsigned char *row = &image[y*stride]; + for (x = 0; x < w; x++) { + int r = row[0], g = row[1], b = row[2], a = row[3]; + if (a != 0) { + row[0] = (unsigned char)(r*255/a); + row[1] = (unsigned char)(g*255/a); + row[2] = (unsigned char)(b*255/a); + } + row += 4; + } + } + + // Defringe + for (y = 0; y < h; y++) { + unsigned char *row = &image[y*stride]; + for (x = 0; x < w; x++) { + int r = 0, g = 0, b = 0, a = row[3], n = 0; + if (a == 0) { + if (x-1 > 0 && row[-1] != 0) { + r += row[-4]; + g += row[-3]; + b += row[-2]; + n++; + } + if (x+1 < w && row[7] != 0) { + r += row[4]; + g += row[5]; + b += row[6]; + n++; + } + if (y-1 > 0 && row[-stride+3] != 0) { + r += row[-stride]; + g += row[-stride+1]; + b += row[-stride+2]; + n++; + } + if (y+1 < h && row[stride+3] != 0) { + r += row[stride]; + g += row[stride+1]; + b += row[stride+2]; + n++; + } + if (n > 0) { + row[0] = (unsigned char)(r/n); + row[1] = (unsigned char)(g/n); + row[2] = (unsigned char)(b/n); + } + } + row += 4; + } + } +} + + +static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) +{ + int i, j; + NSVGgradient* grad; + + cache->type = paint->type; + + if (paint->type == NSVG_PAINT_COLOR) { + cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); + return; + } + + grad = paint->gradient; + + cache->spread = grad->spread; + memcpy(cache->xform, grad->xform, sizeof(float)*6); + + if (grad->nstops == 0) { + for (i = 0; i < 256; i++) + cache->colors[i] = 0; + } if (grad->nstops == 1) { + for (i = 0; i < 256; i++) + cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); + } else { + unsigned int ca, cb = 0; + float ua, ub, du, u; + int ia, ib, count; + + ca = nsvg__applyOpacity(grad->stops[0].color, opacity); + ua = nsvg__clampf(grad->stops[0].offset, 0, 1); + ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); + ia = (int)(ua * 255.0f); + ib = (int)(ub * 255.0f); + for (i = 0; i < ia; i++) { + cache->colors[i] = ca; + } + + for (i = 0; i < grad->nstops-1; i++) { + ca = nsvg__applyOpacity(grad->stops[i].color, opacity); + cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); + ua = nsvg__clampf(grad->stops[i].offset, 0, 1); + ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); + ia = (int)(ua * 255.0f); + ib = (int)(ub * 255.0f); + count = ib - ia; + if (count <= 0) continue; + u = 0; + du = 1.0f / (float)count; + for (j = 0; j < count; j++) { + cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); + u += du; + } + } + + for (i = ib; i < 256; i++) + cache->colors[i] = cb; + } + +} + +/* +static void dumpEdges(NSVGrasterizer* r, const char* name) +{ + float xmin = 0, xmax = 0, ymin = 0, ymax = 0; + NSVGedge *e = NULL; + int i; + if (r->nedges == 0) return; + FILE* fp = fopen(name, "w"); + if (fp == NULL) return; + + xmin = xmax = r->edges[0].x0; + ymin = ymax = r->edges[0].y0; + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + xmin = nsvg__minf(xmin, e->x0); + xmin = nsvg__minf(xmin, e->x1); + xmax = nsvg__maxf(xmax, e->x0); + xmax = nsvg__maxf(xmax, e->x1); + ymin = nsvg__minf(ymin, e->y0); + ymin = nsvg__minf(ymin, e->y1); + ymax = nsvg__maxf(ymax, e->y0); + ymax = nsvg__maxf(ymax, e->y1); + } + + fprintf(fp, "", xmin, ymin, (xmax - xmin), (ymax - ymin)); + + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); + } + + for (i = 0; i < r->npoints; i++) { + if (i+1 < r->npoints) + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); + } + + fprintf(fp, ""); + fclose(fp); +} +*/ + +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride) +{ + NSVGshape *shape = NULL; + NSVGedge *e = NULL; + NSVGcachedPaint cache; + int i; + + r->bitmap = dst; + r->width = w; + r->height = h; + r->stride = stride; + + if (w > r->cscanline) { + r->cscanline = w; + r->scanline = (unsigned char*)realloc(r->scanline, w); + if (r->scanline == NULL) return; + } + + for (i = 0; i < h; i++) + memset(&dst[i*stride], 0, w*4); + + for (shape = image->shapes; shape != NULL; shape = shape->next) { + if (!(shape->flags & NSVG_FLAGS_VISIBLE)) + continue; + + if (shape->fill.type != NSVG_PAINT_NONE) { + nsvg__resetPool(r); + r->freelist = NULL; + r->nedges = 0; + + nsvg__flattenShape(r, shape, scale); + + // Scale and translate edges + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + e->x0 = tx + e->x0; + e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; + e->x1 = tx + e->x1; + e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; + } + + // Rasterize edges + qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); + + // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + nsvg__initPaint(&cache, &shape->fill, shape->opacity); + + nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); + } + if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { + nsvg__resetPool(r); + r->freelist = NULL; + r->nedges = 0; + + nsvg__flattenShapeStroke(r, shape, scale); + +// dumpEdges(r, "edge.svg"); + + // Scale and translate edges + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + e->x0 = tx + e->x0; + e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; + e->x1 = tx + e->x1; + e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; + } + + // Rasterize edges + qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); + + // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + nsvg__initPaint(&cache, &shape->stroke, shape->opacity); + + nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); + } + } + + nsvg__unpremultiplyAlpha(dst, w, h, stride); + + r->bitmap = NULL; + r->width = 0; + r->height = 0; + r->stride = 0; +} + +#endif diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 9d65a479f..157fc9011 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -74,6 +74,8 @@ set(SLIC3R_GUI_SOURCES GUI/BedShapeDialog.hpp GUI/2DBed.cpp GUI/2DBed.hpp + GUI/3DBed.cpp + GUI/3DBed.hpp GUI/wxExtensions.cpp GUI/wxExtensions.hpp GUI/WipeTowerDialog.cpp diff --git a/src/slic3r/GUI/2DBed.cpp b/src/slic3r/GUI/2DBed.cpp index c90d54cb0..eb55d5fdc 100644 --- a/src/slic3r/GUI/2DBed.cpp +++ b/src/slic3r/GUI/2DBed.cpp @@ -1,4 +1,5 @@ #include "2DBed.hpp" +#include "GUI_App.hpp" #include @@ -9,6 +10,19 @@ namespace Slic3r { namespace GUI { + +Bed_2D::Bed_2D(wxWindow* parent) : +wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), -1), wxTAB_TRAVERSAL) +{ + SetBackgroundStyle(wxBG_STYLE_PAINT); // to avoid assert message after wxAutoBufferedPaintDC +#ifdef __APPLE__ + m_user_drawn_background = false; +#endif /*__APPLE__*/ + Bind(wxEVT_PAINT, ([this](wxPaintEvent e) { repaint(); })); + Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent event) { mouse_event(event); })); + Bind(wxEVT_MOTION, ([this](wxMouseEvent event) { mouse_event(event); })); + Bind(wxEVT_SIZE, ([this](wxSizeEvent e) { Refresh(); })); +} void Bed_2D::repaint() { wxAutoBufferedPaintDC dc(this); diff --git a/src/slic3r/GUI/2DBed.hpp b/src/slic3r/GUI/2DBed.hpp index 463561953..579ef4445 100644 --- a/src/slic3r/GUI/2DBed.hpp +++ b/src/slic3r/GUI/2DBed.hpp @@ -25,21 +25,7 @@ class Bed_2D : public wxPanel void set_pos(Vec2d pos); public: - Bed_2D(wxWindow* parent) - { - Create(parent, wxID_ANY, wxDefaultPosition, wxSize(250, -1), wxTAB_TRAVERSAL); - SetBackgroundStyle(wxBG_STYLE_PAINT); // to avoid assert message after wxAutoBufferedPaintDC -// m_user_drawn_background = $^O ne 'darwin'; -#ifdef __APPLE__ - m_user_drawn_background = false; -#endif /*__APPLE__*/ - Bind(wxEVT_PAINT, ([this](wxPaintEvent e) { repaint(); })); -// EVT_ERASE_BACKGROUND($self, sub{}) if $self->{user_drawn_background}; -// Bind(EVT_MOUSE_EVENTS, ([this](wxMouseEvent event) {/*mouse_event()*/; })); - Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent event) { mouse_event(event); })); - Bind(wxEVT_MOTION, ([this](wxMouseEvent event) { mouse_event(event); })); - Bind(wxEVT_SIZE, ([this](wxSizeEvent e) { Refresh(); })); - } + Bed_2D(wxWindow* parent); ~Bed_2D() {} std::vector m_bed_shape; diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp new file mode 100644 index 000000000..236793814 --- /dev/null +++ b/src/slic3r/GUI/3DBed.cpp @@ -0,0 +1,809 @@ +#include "libslic3r/libslic3r.h" + +#include "3DBed.hpp" + +#include "libslic3r/Polygon.hpp" +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/BoundingBox.hpp" + +#include "GUI_App.hpp" +#include "PresetBundle.hpp" + +#include + +#include + +static const float GROUND_Z = -0.02f; + +namespace Slic3r { +namespace GUI { + +bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords) +{ +#if ENABLE_TEXTURES_FROM_SVG + m_vertices.clear(); + unsigned int v_size = 3 * (unsigned int)triangles.size(); + + if (v_size == 0) + return false; + + m_vertices = std::vector(v_size, Vertex()); + + float min_x = unscale(triangles[0].points[0](0)); + float min_y = unscale(triangles[0].points[0](1)); + float max_x = min_x; + float max_y = min_y; + + unsigned int v_count = 0; + for (const Polygon& t : triangles) + { + for (unsigned int i = 0; i < 3; ++i) + { + Vertex& v = m_vertices[v_count]; + + const Point& p = t.points[i]; + float x = unscale(p(0)); + float y = unscale(p(1)); + + v.position[0] = x; + v.position[1] = y; + v.position[2] = z; + + if (generate_tex_coords) + { + v.tex_coords[0] = x; + v.tex_coords[1] = y; + + min_x = std::min(min_x, x); + max_x = std::max(max_x, x); + min_y = std::min(min_y, y); + max_y = std::max(max_y, y); + } + + ++v_count; + } + } + + if (generate_tex_coords) + { + float size_x = max_x - min_x; + float size_y = max_y - min_y; + + if ((size_x != 0.0f) && (size_y != 0.0f)) + { + float inv_size_x = 1.0f / size_x; + float inv_size_y = -1.0f / size_y; + for (Vertex& v : m_vertices) + { + v.tex_coords[0] = (v.tex_coords[0] - min_x) * inv_size_x; + v.tex_coords[1] = (v.tex_coords[1] - min_y) * inv_size_y; + } + } + } +#else + m_vertices.clear(); + m_tex_coords.clear(); + + unsigned int v_size = 9 * (unsigned int)triangles.size(); + unsigned int t_size = 6 * (unsigned int)triangles.size(); + if (v_size == 0) + return false; + + m_vertices = std::vector(v_size, 0.0f); + if (generate_tex_coords) + m_tex_coords = std::vector(t_size, 0.0f); + + float min_x = unscale(triangles[0].points[0](0)); + float min_y = unscale(triangles[0].points[0](1)); + float max_x = min_x; + float max_y = min_y; + + unsigned int v_coord = 0; + unsigned int t_coord = 0; + for (const Polygon& t : triangles) + { + for (unsigned int v = 0; v < 3; ++v) + { + const Point& p = t.points[v]; + float x = unscale(p(0)); + float y = unscale(p(1)); + + m_vertices[v_coord++] = x; + m_vertices[v_coord++] = y; + m_vertices[v_coord++] = z; + + if (generate_tex_coords) + { + m_tex_coords[t_coord++] = x; + m_tex_coords[t_coord++] = y; + + min_x = std::min(min_x, x); + max_x = std::max(max_x, x); + min_y = std::min(min_y, y); + max_y = std::max(max_y, y); + } + } + } + + if (generate_tex_coords) + { + float size_x = max_x - min_x; + float size_y = max_y - min_y; + + if ((size_x != 0.0f) && (size_y != 0.0f)) + { + float inv_size_x = 1.0f / size_x; + float inv_size_y = -1.0f / size_y; + for (unsigned int i = 0; i < m_tex_coords.size(); i += 2) + { + m_tex_coords[i] = (m_tex_coords[i] - min_x) * inv_size_x; + m_tex_coords[i + 1] = (m_tex_coords[i + 1] - min_y) * inv_size_y; + } + } + } +#endif // ENABLE_TEXTURES_FROM_SVG + + return true; +} + +bool GeometryBuffer::set_from_lines(const Lines& lines, float z) +{ +#if ENABLE_TEXTURES_FROM_SVG + m_vertices.clear(); + + unsigned int v_size = 2 * (unsigned int)lines.size(); + if (v_size == 0) + return false; + + m_vertices = std::vector(v_size, Vertex()); + + unsigned int v_count = 0; + for (const Line& l : lines) + { + Vertex& v1 = m_vertices[v_count]; + v1.position[0] = unscale(l.a(0)); + v1.position[1] = unscale(l.a(1)); + v1.position[2] = z; + ++v_count; + + Vertex& v2 = m_vertices[v_count]; + v2.position[0] = unscale(l.b(0)); + v2.position[1] = unscale(l.b(1)); + v2.position[2] = z; + ++v_count; + } +#else + m_vertices.clear(); + m_tex_coords.clear(); + + unsigned int size = 6 * (unsigned int)lines.size(); + if (size == 0) + return false; + + m_vertices = std::vector(size, 0.0f); + + unsigned int coord = 0; + for (const Line& l : lines) + { + m_vertices[coord++] = unscale(l.a(0)); + m_vertices[coord++] = unscale(l.a(1)); + m_vertices[coord++] = z; + m_vertices[coord++] = unscale(l.b(0)); + m_vertices[coord++] = unscale(l.b(1)); + m_vertices[coord++] = z; + } +#endif // ENABLE_TEXTURES_FROM_SVG + + return true; +} + +#if ENABLE_TEXTURES_FROM_SVG +const float* GeometryBuffer::get_vertices_data() const +{ + return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr; +} +#endif // ENABLE_TEXTURES_FROM_SVG + +const double Bed3D::Axes::Radius = 0.5; +const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius; +const double Bed3D::Axes::ArrowLength = 5.0; + +Bed3D::Axes::Axes() +: origin(Vec3d::Zero()) +, length(Vec3d::Zero()) +{ + m_quadric = ::gluNewQuadric(); + if (m_quadric != nullptr) + ::gluQuadricDrawStyle(m_quadric, GLU_FILL); +} + +Bed3D::Axes::~Axes() +{ + if (m_quadric != nullptr) + ::gluDeleteQuadric(m_quadric); +} + +void Bed3D::Axes::render() const +{ + if (m_quadric == nullptr) + return; + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_LIGHTING)); + + // x axis + glsafe(::glColor3f(1.0f, 0.0f, 0.0f)); + glsafe(::glPushMatrix()); + glsafe(::glTranslated(origin(0), origin(1), origin(2))); + glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); + render_axis(length(0)); + glsafe(::glPopMatrix()); + + // y axis + glsafe(::glColor3f(0.0f, 1.0f, 0.0f)); + glsafe(::glPushMatrix()); + glsafe(::glTranslated(origin(0), origin(1), origin(2))); + glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); + render_axis(length(1)); + glsafe(::glPopMatrix()); + + // z axis + glsafe(::glColor3f(0.0f, 0.0f, 1.0f)); + glsafe(::glPushMatrix()); + glsafe(::glTranslated(origin(0), origin(1), origin(2))); + render_axis(length(2)); + glsafe(::glPopMatrix()); + + glsafe(::glDisable(GL_LIGHTING)); +} + +void Bed3D::Axes::render_axis(double length) const +{ + ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); + ::gluCylinder(m_quadric, Radius, Radius, length, 32, 1); + ::gluQuadricOrientation(m_quadric, GLU_INSIDE); + ::gluDisk(m_quadric, 0.0, Radius, 32, 1); + glsafe(::glTranslated(0.0, 0.0, length)); + ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); + ::gluCylinder(m_quadric, ArrowBaseRadius, 0.0, ArrowLength, 32, 1); + ::gluQuadricOrientation(m_quadric, GLU_INSIDE); + ::gluDisk(m_quadric, 0.0, ArrowBaseRadius, 32, 1); +} + +Bed3D::Bed3D() + : m_type(Custom) +#if ENABLE_TEXTURES_FROM_SVG + , m_vbo_id(0) +#endif // ENABLE_TEXTURES_FROM_SVG + , m_scale_factor(1.0f) +{ +} + +bool Bed3D::set_shape(const Pointfs& shape) +{ + EType new_type = detect_type(shape); + if (m_shape == shape && m_type == new_type) + // No change, no need to update the UI. + return false; + + m_shape = shape; + m_type = new_type; + + calc_bounding_box(); + + ExPolygon poly; + for (const Vec2d& p : m_shape) + { + poly.contour.append(Point(scale_(p(0)), scale_(p(1)))); + } + + calc_triangles(poly); + + const BoundingBox& bed_bbox = poly.contour.bounding_box(); + calc_gridlines(poly, bed_bbox); + + m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour; + +#if ENABLE_TEXTURES_FROM_SVG + reset(); +#endif // ENABLE_TEXTURES_FROM_SVG + + // Set the origin and size for painting of the coordinate system axes. + m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); + m_axes.length = 0.1 * get_bounding_box().max_size() * Vec3d::Ones(); + + // Let the calee to update the UI. + return true; +} + +bool Bed3D::contains(const Point& point) const +{ + return m_polygon.contains(point); +} + +Point Bed3D::point_projection(const Point& point) const +{ + return m_polygon.point_projection(point); +} + +#if ENABLE_TEXTURES_FROM_SVG +void Bed3D::render(float theta, bool useVBOs, float scale_factor) const +{ + m_scale_factor = scale_factor; + + EType type = useVBOs ? m_type : Custom; + switch (type) + + { + case MK2: + { + render_prusa("mk2", theta > 90.0f); + break; + } + case MK3: + { + render_prusa("mk3", theta > 90.0f); + break; + } + case SL1: + { + render_prusa("sl1", theta > 90.0f); + break; + } + default: + case Custom: + { + render_custom(); + break; + } + } +} +#else +void Bed3D::render(float theta, bool useVBOs, float scale_factor) const +{ + m_scale_factor = scale_factor; + + if (m_shape.empty()) + return; + + switch (m_type) + { + case MK2: + { + render_prusa("mk2", theta, useVBOs); + break; + } + case MK3: + { + render_prusa("mk3", theta, useVBOs); + break; + } + case SL1: + { + render_prusa("sl1", theta, useVBOs); + break; + } + default: + case Custom: + { + render_custom(); + break; + } + } +} +#endif // ENABLE_TEXTURES_FROM_SVG + +void Bed3D::render_axes() const +{ + if (!m_shape.empty()) + m_axes.render(); +} + +void Bed3D::calc_bounding_box() +{ + m_bounding_box = BoundingBoxf3(); + for (const Vec2d& p : m_shape) + { + m_bounding_box.merge(Vec3d(p(0), p(1), 0.0)); + } +} + +void Bed3D::calc_triangles(const ExPolygon& poly) +{ + Polygons triangles; + poly.triangulate(&triangles); + + if (!m_triangles.set_from_triangles(triangles, GROUND_Z, m_type != Custom)) + printf("Unable to create bed triangles\n"); +} + +void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) +{ + Polylines axes_lines; + for (coord_t x = bed_bbox.min(0); x <= bed_bbox.max(0); x += scale_(10.0)) + { + Polyline line; + line.append(Point(x, bed_bbox.min(1))); + line.append(Point(x, bed_bbox.max(1))); + axes_lines.push_back(line); + } + for (coord_t y = bed_bbox.min(1); y <= bed_bbox.max(1); y += scale_(10.0)) + { + Polyline line; + line.append(Point(bed_bbox.min(0), y)); + line.append(Point(bed_bbox.max(0), y)); + axes_lines.push_back(line); + } + + // clip with a slightly grown expolygon because our lines lay on the contours and may get erroneously clipped + Lines gridlines = to_lines(intersection_pl(axes_lines, offset(poly, (float)SCALED_EPSILON))); + + // append bed contours + Lines contour_lines = to_lines(poly); + std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); + + if (!m_gridlines.set_from_lines(gridlines, GROUND_Z)) + printf("Unable to create bed grid lines\n"); +} + +Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const +{ + EType type = Custom; + + auto bundle = wxGetApp().preset_bundle; + if (bundle != nullptr) + { + const Preset* curr = &bundle->printers.get_selected_preset(); + while (curr != nullptr) + { + if (curr->config.has("bed_shape")) + { + if ((curr->vendor != nullptr) && (curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) + { + if (boost::contains(curr->name, "SL1")) + { + type = SL1; + break; + } + else if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5")) + { + type = MK3; + break; + } + else if (boost::contains(curr->name, "MK2")) + { + type = MK2; + break; + } + } + } + + curr = bundle->printers.get_preset_parent(*curr); + } + } + + return type; +} + +#if ENABLE_TEXTURES_FROM_SVG +void Bed3D::render_prusa(const std::string &key, bool bottom) const +{ + std::string tex_path = resources_dir() + "/icons/bed/" + key; + + std::string model_path = resources_dir() + "/models/" + key; + + // use anisotropic filter if graphic card allows + GLfloat max_anisotropy = 0.0f; + if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) + ::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); + + // use higher resolution images if graphic card allows + GLint max_tex_size; + ::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); + + // clamp or the texture generation becomes too slow + max_tex_size = std::min(max_tex_size, 8192); + + std::string filename = tex_path + ".svg"; + + if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) + { + if (!m_texture.load_from_svg_file(filename, true, max_tex_size)) + { + render_custom(); + return; + } + + if (max_anisotropy > 0.0f) + { + glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + } + } + + if (!bottom) + { + filename = model_path + "_bed.stl"; + if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, true)) { + Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2)); + if (key == "mk2") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 7.5, -0.03); + else if (key == "mk3") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 5.5, 2.43); + else if (key == "sl1") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 0.0, -0.03); + + m_model.center_around(offset); + } + + if (!m_model.get_filename().empty()) + { + glsafe(::glEnable(GL_LIGHTING)); + m_model.render(); + glsafe(::glDisable(GL_LIGHTING)); + } + } + + unsigned int triangles_vcount = m_triangles.get_vertices_count(); + if (triangles_vcount > 0) + { + if (m_vbo_id == 0) + { + glsafe(::glGenBuffers(1, &m_vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + } + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDepthMask(GL_FALSE)); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + if (bottom) + glsafe(::glFrontFace(GL_CW)); + + render_prusa_shader(bottom); + + if (bottom) + glsafe(::glFrontFace(GL_CCW)); + + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDepthMask(GL_TRUE)); + } +} + +void Bed3D::render_prusa_shader(bool transparent) const +{ + if (m_shader.get_shader_program_id() == 0) + m_shader.init("printbed.vs", "printbed.fs"); + + if (m_shader.is_initialized()) + { + m_shader.start_using(); + m_shader.set_uniform("transparent_background", transparent); + + unsigned int stride = m_triangles.get_vertex_data_size(); + + GLint position_id = m_shader.get_attrib_location("v_position"); + GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords"); + + glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id())); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); + + if (position_id != -1) + { + glsafe(::glEnableVertexAttribArray(position_id)); + glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); + } + if (tex_coords_id != -1) + { + glsafe(::glEnableVertexAttribArray(tex_coords_id)); + glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); + } + + glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count())); + + if (tex_coords_id != -1) + glsafe(::glDisableVertexAttribArray(tex_coords_id)); + + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + + m_shader.stop_using(); + } +} + +#else +void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) const +{ + std::string tex_path = resources_dir() + "/icons/bed/" + key; + + // use higher resolution images if graphic card allows + GLint max_tex_size; + ::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); + + // temporary set to lowest resolution + max_tex_size = 2048; + + if (max_tex_size >= 8192) + tex_path += "_8192"; + else if (max_tex_size >= 4096) + tex_path += "_4096"; + + std::string model_path = resources_dir() + "/models/" + key; + + // use anisotropic filter if graphic card allows + GLfloat max_anisotropy = 0.0f; + if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) + ::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); + + std::string filename = tex_path + "_top.png"; + if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) + { + if (!m_top_texture.load_from_file(filename, true)) + { + render_custom(); + return; + } + + if (max_anisotropy > 0.0f) + { + glsafe(::glBindTexture(GL_TEXTURE_2D, m_top_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + } + } + + filename = tex_path + "_bottom.png"; + if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename)) + { + if (!m_bottom_texture.load_from_file(filename, true)) + { + render_custom(); + return; + } + + if (max_anisotropy > 0.0f) + { + glsafe(::glBindTexture(GL_TEXTURE_2D, m_bottom_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + } + } + + if (theta <= 90.0f) + { + filename = model_path + "_bed.stl"; + if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, useVBOs)) { + Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2)); + if (key == "mk2") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 7.5, -0.03); + else if (key == "mk3") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 5.5, 2.43); + else if (key == "sl1") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 0.0, -0.03); + + m_model.center_around(offset); + } + + if (!m_model.get_filename().empty()) + { + glsafe(::glEnable(GL_LIGHTING)); + m_model.render(); + glsafe(::glDisable(GL_LIGHTING)); + } + } + + unsigned int triangles_vcount = m_triangles.get_vertices_count(); + if (triangles_vcount > 0) + { + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDepthMask(GL_FALSE)); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + glsafe(::glEnable(GL_TEXTURE_2D)); + glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); + + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + + if (theta > 90.0f) + glsafe(::glFrontFace(GL_CW)); + + glsafe(::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id())); + glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices())); + glsafe(::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords())); + glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + + if (theta > 90.0f) + glsafe(::glFrontFace(GL_CCW)); + + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); + glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + glsafe(::glDisable(GL_TEXTURE_2D)); + + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDepthMask(GL_TRUE)); + } +} +#endif // ENABLE_TEXTURES_FROM_SVG + +void Bed3D::render_custom() const +{ +#if ENABLE_TEXTURES_FROM_SVG + m_texture.reset(); +#else + m_top_texture.reset(); + m_bottom_texture.reset(); +#endif // ENABLE_TEXTURES_FROM_SVG + + unsigned int triangles_vcount = m_triangles.get_vertices_count(); + if (triangles_vcount > 0) + { + glsafe(::glEnable(GL_LIGHTING)); + glsafe(::glDisable(GL_DEPTH_TEST)); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + + glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f)); + glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); +#if ENABLE_TEXTURES_FROM_SVG + glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data())); +#else + glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices())); +#endif // ENABLE_TEXTURES_FROM_SVG + glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + + // draw grid + unsigned int gridlines_vcount = m_gridlines.get_vertices_count(); + + // we need depth test for grid, otherwise it would disappear when looking the object from below + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glLineWidth(3.0f * m_scale_factor)); + glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f)); +#if ENABLE_TEXTURES_FROM_SVG + glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data())); +#else + glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices())); +#endif // ENABLE_TEXTURES_FROM_SVG + glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)gridlines_vcount)); + + glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDisable(GL_LIGHTING)); + } +} + +#if ENABLE_TEXTURES_FROM_SVG +void Bed3D::reset() +{ + if (m_vbo_id > 0) + { + glsafe(::glDeleteBuffers(1, &m_vbo_id)); + m_vbo_id = 0; + } +} +#endif // ENABLE_TEXTURES_FROM_SVG + +} // GUI +} // Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp new file mode 100644 index 000000000..e60cdf94e --- /dev/null +++ b/src/slic3r/GUI/3DBed.hpp @@ -0,0 +1,147 @@ +#ifndef slic3r_3DBed_hpp_ +#define slic3r_3DBed_hpp_ + +#include "GLTexture.hpp" +#include "3DScene.hpp" +#if ENABLE_TEXTURES_FROM_SVG +#include "GLShader.hpp" +#endif // ENABLE_TEXTURES_FROM_SVG + +class GLUquadric; +typedef class GLUquadric GLUquadricObj; + +namespace Slic3r { +namespace GUI { + +class GeometryBuffer +{ +#if ENABLE_TEXTURES_FROM_SVG + struct Vertex + { + float position[3]; + float tex_coords[2]; + + Vertex() + { + position[0] = 0.0f; position[1] = 0.0f; position[2] = 0.0f; + tex_coords[0] = 0.0f; tex_coords[1] = 0.0f; + } + }; + + std::vector m_vertices; +#else + std::vector m_vertices; + std::vector m_tex_coords; +#endif // ENABLE_TEXTURES_FROM_SVG + +public: + bool set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords); + bool set_from_lines(const Lines& lines, float z); + +#if ENABLE_TEXTURES_FROM_SVG + const float* get_vertices_data() const; + unsigned int get_vertices_data_size() const { return (unsigned int)m_vertices.size() * get_vertex_data_size(); } + unsigned int get_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); } + unsigned int get_position_offset() const { return 0; } + unsigned int get_tex_coords_offset() const { return (unsigned int)(3 * sizeof(float)); } + unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); } +#else + const float* get_vertices() const { return m_vertices.data(); } + const float* get_tex_coords() const { return m_tex_coords.data(); } + unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size() / 3; } +#endif // ENABLE_TEXTURES_FROM_SVG +}; + +class Bed3D +{ + struct Axes + { + static const double Radius; + static const double ArrowBaseRadius; + static const double ArrowLength; + Vec3d origin; + Vec3d length; + GLUquadricObj* m_quadric; + + Axes(); + ~Axes(); + + void render() const; + + private: + void render_axis(double length) const; + }; + +public: + enum EType : unsigned char + { + MK2, + MK3, + SL1, + Custom, + Num_Types + }; + +private: + EType m_type; + Pointfs m_shape; + BoundingBoxf3 m_bounding_box; + Polygon m_polygon; + GeometryBuffer m_triangles; + GeometryBuffer m_gridlines; +#if ENABLE_TEXTURES_FROM_SVG + mutable GLTexture m_texture; + mutable Shader m_shader; + mutable unsigned int m_vbo_id; +#else + mutable GLTexture m_top_texture; + mutable GLTexture m_bottom_texture; +#endif // ENABLE_TEXTURES_FROM_SVG + mutable GLBed m_model; + Axes m_axes; + + mutable float m_scale_factor; + +public: + Bed3D(); +#if ENABLE_TEXTURES_FROM_SVG + ~Bed3D() { reset(); } +#endif // ENABLE_TEXTURES_FROM_SVG + + EType get_type() const { return m_type; } + + bool is_prusa() const { return (m_type == MK2) || (m_type == MK3) || (m_type == SL1); } + bool is_custom() const { return m_type == Custom; } + + const Pointfs& get_shape() const { return m_shape; } + // Return true if the bed shape changed, so the calee will update the UI. + bool set_shape(const Pointfs& shape); + + const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } + bool contains(const Point& point) const; + Point point_projection(const Point& point) const; + + void render(float theta, bool useVBOs, float scale_factor) const; + void render_axes() const; + +private: + void calc_bounding_box(); + void calc_triangles(const ExPolygon& poly); + void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); + EType detect_type(const Pointfs& shape) const; +#if ENABLE_TEXTURES_FROM_SVG + void render_prusa(const std::string& key, bool bottom) const; + void render_prusa_shader(bool transparent) const; +#else + void render_prusa(const std::string &key, float theta, bool useVBOs) const; +#endif // ENABLE_TEXTURES_FROM_SVG + void render_custom() const; +#if ENABLE_TEXTURES_FROM_SVG + void reset(); +#endif // ENABLE_TEXTURES_FROM_SVG +}; + +} // GUI +} // Slic3r + +#endif // slic3r_3DBed_hpp_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index f8b717d69..3bf54043b 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -11,9 +11,7 @@ #include "libslic3r/Slicing.hpp" #include "libslic3r/GCode/Analyzer.hpp" #include "slic3r/GUI/PresetBundle.hpp" -#if ENABLE_PRINT_BED_MODELS #include "libslic3r/Format/STL.hpp" -#endif // ENABLE_PRINT_BED_MODELS #include #include @@ -23,10 +21,8 @@ #include -#if ENABLE_PRINT_BED_MODELS #include #include -#endif // ENABLE_PRINT_BED_MODELS #include #include @@ -793,7 +789,7 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool glsafe(::glDisable(GL_BLEND)); } -void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface) const +void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface, std::function filter_func) const { glsafe(glEnable(GL_BLEND)); glsafe(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); @@ -805,7 +801,7 @@ void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface) glsafe(glEnableClientState(GL_VERTEX_ARRAY)); glsafe(glEnableClientState(GL_NORMAL_ARRAY)); - GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, std::function()); + GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, filter_func); for (GLVolumeWithZ& volume : to_render) { volume.first->set_render_color(); @@ -1667,27 +1663,19 @@ GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; GLModel::GLModel() : m_useVBOs(false) -#if ENABLE_PRINT_BED_MODELS , m_filename("") -#endif // ENABLE_PRINT_BED_MODELS { m_volume.shader_outside_printer_detection_enabled = false; } GLModel::~GLModel() { -#if ENABLE_PRINT_BED_MODELS reset(); -#else - m_volume.release_geometry(); -#endif // ENABLE_PRINT_BED_MODELS } void GLModel::set_color(const float* color, unsigned int size) { -#if ENABLE_PRINT_BED_MODELS ::memcpy((void*)m_volume.color, (const void*)color, (size_t)(std::min((unsigned int)4, size) * sizeof(float))); -#endif // ENABLE_PRINT_BED_MODELS m_volume.set_render_color(color, size); } @@ -1721,13 +1709,11 @@ void GLModel::set_scale(const Vec3d& scale) m_volume.set_volume_scaling_factor(scale); } -#if ENABLE_PRINT_BED_MODELS void GLModel::reset() { m_volume.release_geometry(); m_filename = ""; } -#endif // ENABLE_PRINT_BED_MODELS void GLModel::render() const { @@ -1964,7 +1950,6 @@ bool GLCurvedArrow::on_init(bool useVBOs) return true; } -#if ENABLE_PRINT_BED_MODELS bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) { reset(); @@ -2007,7 +1992,6 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) return true; } -#endif // ENABLE_PRINT_BED_MODELS std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) { diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index a02497116..805383ef4 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -457,7 +457,7 @@ public: // Render the volumes by OpenGL. void render_VBOs(ERenderType type, bool disable_cullface, std::function filter_func = std::function()) const; - void render_legacy(ERenderType type, bool disable_cullface) const; + void render_legacy(ERenderType type, bool disable_cullface, std::function filter_func = std::function()) const; // Finalize the initialization of the geometry & indices, // upload the geometry and indices to OpenGL VBO objects @@ -499,20 +499,16 @@ class GLModel protected: GLVolume m_volume; bool m_useVBOs; -#if ENABLE_PRINT_BED_MODELS std::string m_filename; -#endif // ENABLE_PRINT_BED_MODELS public: GLModel(); virtual ~GLModel(); bool init(bool useVBOs) { return on_init(useVBOs); } -#if ENABLE_PRINT_BED_MODELS bool init_from_file(const std::string& filename, bool useVBOs) { return on_init_from_file(filename, useVBOs); } void center_around(const Vec3d& center) { m_volume.set_volume_offset(center - m_volume.bounding_box.center()); } -#endif // ENABLE_PRINT_BED_MODELS void set_color(const float* color, unsigned int size); const Vec3d& get_offset() const; @@ -522,22 +518,16 @@ public: const Vec3d& get_scale() const; void set_scale(const Vec3d& scale); -#if ENABLE_PRINT_BED_MODELS const std::string& get_filename() const { return m_filename; } const BoundingBoxf3& get_bounding_box() const { return m_volume.bounding_box; } void reset(); -#endif // ENABLE_PRINT_BED_MODELS void render() const; protected: -#if ENABLE_PRINT_BED_MODELS virtual bool on_init(bool useVBOs) { return false; } virtual bool on_init_from_file(const std::string& filename, bool useVBOs) { return false; } -#else - virtual bool on_init(bool useVBOs) = 0; -#endif // ENABLE_PRINT_BED_MODELS private: void render_VBOs() const; @@ -561,13 +551,11 @@ protected: virtual bool on_init(bool useVBOs); }; -#if ENABLE_PRINT_BED_MODELS class GLBed : public GLModel { protected: virtual bool on_init_from_file(const std::string& filename, bool useVBOs); }; -#endif // ENABLE_PRINT_BED_MODELS class _3DScene { diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index c3d75ef57..6b1795b66 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -2,6 +2,8 @@ #include "I18N.hpp" #include "libslic3r/Utils.hpp" +#include "GUI_App.hpp" +#include "wxExtensions.hpp" namespace Slic3r { namespace GUI { @@ -40,17 +42,13 @@ AboutDialog::AboutDialog() main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20); // logo - wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG); - auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(logo_bmp)); - hsizer->Add(logo, 1, wxEXPAND | wxTOP | wxBOTTOM, 35); +// wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG); +// auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(logo_bmp)); + auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png")); + hsizer->Add(logo, 1, wxALIGN_CENTER_VERTICAL); - wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); -#ifdef __WXMSW__ - int proportion = 2; -#else - int proportion = 3; -#endif - hsizer->Add(vsizer, proportion, wxEXPAND|wxLEFT, 20); + wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); + hsizer->Add(vsizer, 2, wxEXPAND|wxLEFT, 20); // title { @@ -80,6 +78,7 @@ AboutDialog::AboutDialog() // text wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO/*NEVER*/); { + html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit())); wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); const auto text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index b8a8633d3..b62825102 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -150,7 +150,7 @@ void BackgroundSlicingProcess::process_sla() if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { m_sla_print->export_raster(m_export_path); - m_print->set_status(100, "Zip file exported to " + m_export_path); + m_print->set_status(100, "Masked SLA file exported to " + m_export_path); } else if (! m_upload_job.empty()) { prepare_upload(); } else { @@ -196,6 +196,7 @@ void BackgroundSlicingProcess::thread_proc() } catch (...) { error = "Unknown C++ exception."; } + m_print->finalize(); lck.lock(); m_state = m_print->canceled() ? STATE_CANCELED : STATE_FINISHED; if (m_print->cancel_status() != Print::CANCELED_INTERNAL) { @@ -362,6 +363,12 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn return invalidated; } +void BackgroundSlicingProcess::set_task(const PrintBase::TaskParams ¶ms) +{ + assert(m_print != nullptr); + m_print->set_task(params); +} + // Set the output path of the G-code. void BackgroundSlicingProcess::schedule_export(const std::string &path) { diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 5911c8a02..a2299e7bf 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -78,6 +78,9 @@ public: // Apply config over the print. Returns false, if the new config values caused any of the already // processed steps to be invalidated, therefore the task will need to be restarted. Print::ApplyStatus apply(const Model &model, const DynamicPrintConfig &config); + // After calling the apply() function, set_task() may be called to limit the task to be processed by process(). + // This is useful for calculating SLA supports for a single object only. + void set_task(const PrintBase::TaskParams ¶ms); // After calling apply, the empty() call will report whether there is anything to slice. bool empty() const; // Validate the print. Returns an empty string if valid, returns an error message if invalid. @@ -94,6 +97,7 @@ public: void reset_export(); // Once the G-code export is scheduled, the apply() methods will do nothing. bool is_export_scheduled() const { return ! m_export_path.empty(); } + bool is_upload_scheduled() const { return ! m_upload_job.empty(); } enum State { // m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet). diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index feb44a922..7bbf1ac7f 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -44,7 +44,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt) auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL); // shape options - m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxSize(300, -1), wxCHB_TOP); + m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, + wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP); sbsizer->Add(m_shape_options_book); auto optgroup = init_shape_options_page(_(L("Rectangular"))); @@ -124,7 +125,7 @@ ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(wxString title) ConfigOptionsGroupShp optgroup; optgroup = std::make_shared(panel, _(L("Settings"))); - optgroup->label_width = 100; + optgroup->label_width = 10*wxGetApp().em_unit();//100; optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { update_shape(); }; diff --git a/src/slic3r/GUI/BedShapeDialog.hpp b/src/slic3r/GUI/BedShapeDialog.hpp index 84752c3fc..538fccc34 100644 --- a/src/slic3r/GUI/BedShapeDialog.hpp +++ b/src/slic3r/GUI/BedShapeDialog.hpp @@ -42,7 +42,7 @@ class BedShapeDialog : public wxDialog BedShapePanel* m_panel; public: BedShapeDialog(wxWindow* parent) : wxDialog(parent, wxID_ANY, _(L("Bed Shape")), - wxDefaultPosition, wxSize(350, 700), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {} + wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {} ~BedShapeDialog() {} void build_dialog(ConfigOptionPoints* default_pt); diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index dc396895b..422f683b3 100644 --- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -5,6 +5,7 @@ #include "../Utils/Time.hpp" #include "libslic3r/Utils.hpp" +#include "GUI_App.hpp" namespace Slic3r { namespace GUI { @@ -94,7 +95,9 @@ static wxString generate_html_page(const Config::SnapshotDB &snapshot_db, const } ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db, const wxString &on_snapshot) - : wxDialog(NULL, wxID_ANY, _(L("Configuration Snapshots")), wxDefaultPosition, wxSize(600, 500), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX) + : wxDialog(NULL, wxID_ANY, _(L("Configuration Snapshots")), wxDefaultPosition, + wxSize(45 * wxGetApp().em_unit(), 40 * wxGetApp().em_unit()), + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX) { this->SetBackgroundColour(*wxWHITE); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 23ebdee87..bf4afab3a 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1,10 +1,12 @@ #include "ConfigWizard_private.hpp" #include +#include #include #include #include #include +#include #include #include @@ -13,10 +15,15 @@ #include #include #include +#include +#include +#include +#include #include "libslic3r/Utils.hpp" #include "PresetBundle.hpp" #include "GUI.hpp" +#include "GUI_Utils.hpp" #include "slic3r/Utils/PresetUpdater.hpp" @@ -34,12 +41,12 @@ struct PrinterPickerEvent : public wxEvent std::string variant_name; bool enable; - PrinterPickerEvent(wxEventType eventType, int winid, std::string vendor_id, std::string model_id, std::string variant_name, bool enable) : - wxEvent(winid, eventType), - vendor_id(std::move(vendor_id)), - model_id(std::move(model_id)), - variant_name(std::move(variant_name)), - enable(enable) + PrinterPickerEvent(wxEventType eventType, int winid, std::string vendor_id, std::string model_id, std::string variant_name, bool enable) + : wxEvent(winid, eventType) + , vendor_id(std::move(vendor_id)) + , model_id(std::move(model_id)) + , variant_name(std::move(variant_name)) + , enable(enable) {} virtual wxEvent *Clone() const @@ -50,21 +57,18 @@ struct PrinterPickerEvent : public wxEvent wxDEFINE_EVENT(EVT_PRINTER_PICK, PrinterPickerEvent); -PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors) : - wxPanel(parent), - vendor_id(vendor.id), - variants_checked(0) +PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors, const ModelFilter &filter) + : wxPanel(parent) + , vendor_id(vendor.id) + , width(0) { const auto &models = vendor.models; auto *sizer = new wxBoxSizer(wxVERTICAL); - auto *printer_grid = new wxFlexGridSizer(models.size(), 0, 20); - printer_grid->SetFlexibleDirection(wxVERTICAL | wxHORIZONTAL); - sizer->Add(printer_grid); - - auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - namefont.SetWeight(wxFONTWEIGHT_BOLD); + const auto font_title = GetFont().MakeBold().Scaled(1.3f); + const auto font_name = GetFont().MakeBold(); + const auto font_alt_nozzle = GetFont().Scaled(0.9f); // wxGrid appends widgets by rows, but we need to construct them in columns. // These vectors are used to hold the elements so that they can be appended in the right order. @@ -72,12 +76,25 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons std::vector bitmaps; std::vector variants_panels; + int max_row_width = 0; + int current_row_width = 0; + for (const auto &model : models) { + if (! filter(model)) { continue; } + wxBitmap bitmap(GUI::from_u8(Slic3r::var((boost::format("printers/%1%_%2%.png") % vendor.id % model.id).str())), wxBITMAP_TYPE_PNG); auto *title = new wxStaticText(this, wxID_ANY, model.name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - title->SetFont(namefont); - title->Wrap(std::max((int)MODEL_MIN_WRAP, bitmap.GetWidth())); + title->SetFont(font_name); + const int wrap_width = std::max((int)MODEL_MIN_WRAP, bitmap.GetWidth()); + title->Wrap(wrap_width); + + current_row_width += wrap_width; + if (titles.size() % max_cols == max_cols - 1) { + max_row_width = std::max(max_row_width, current_row_width); + current_row_width = 0; + } + titles.push_back(title); auto *bitmap_widget = new wxStaticBitmap(this, wxID_ANY, bitmap); @@ -88,46 +105,102 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons variants_panel->SetSizer(variants_sizer); const auto model_id = model.id; - bool default_variant = true; // Mark the first variant as default in the GUI - for (const auto &variant : model.variants) { - const auto label = wxString::Format("%s %s %s %s", variant.name, _(L("mm")), _(L("nozzle")), - (default_variant ? "(" + _(L("default")) + ")" : wxString())); - default_variant = false; + for (size_t i = 0; i < model.variants.size(); i++) { + const auto &variant = model.variants[i]; + + const auto label = model.technology == ptFFF + ? wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle"))) + : from_u8(model.name); + + if (i == 1) { + auto *alt_label = new wxStaticText(variants_panel, wxID_ANY, _(L("Alternate nozzles:"))); + alt_label->SetFont(font_alt_nozzle); + variants_sizer->Add(alt_label, 0, wxBOTTOM, 3); + } + auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name); - const size_t idx = cboxes.size(); - cboxes.push_back(cbox); + i == 0 ? cboxes.push_back(cbox) : cboxes_alt.push_back(cbox); + bool enabled = appconfig_vendors.get_variant(MAIN_VENDOR, model_id, variant.name); - variants_checked += enabled; cbox->SetValue(enabled); + variants_sizer->Add(cbox, 0, wxBOTTOM, 3); - cbox->Bind(wxEVT_CHECKBOX, [this, idx](wxCommandEvent &event) { - if (idx >= this->cboxes.size()) { return; } - this->on_checkbox(this->cboxes[idx], event.IsChecked()); + + cbox->Bind(wxEVT_CHECKBOX, [this, cbox](wxCommandEvent &event) { + on_checkbox(cbox, event.IsChecked()); }); } variants_panels.push_back(variants_panel); } - for (auto title : titles) { printer_grid->Add(title, 0, wxBOTTOM, 3); } - for (auto bitmap : bitmaps) { printer_grid->Add(bitmap, 0, wxBOTTOM, 20); } - for (auto vp : variants_panels) { printer_grid->Add(vp); } + width = std::max(max_row_width, current_row_width); - auto *all_none_sizer = new wxBoxSizer(wxHORIZONTAL); - auto *sel_all = new wxButton(this, wxID_ANY, _(L("Select all"))); - auto *sel_none = new wxButton(this, wxID_ANY, _(L("Select none"))); - sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(true); }); + const size_t cols = std::min(max_cols, titles.size()); + + auto *printer_grid = new wxFlexGridSizer(cols, 0, 20); + printer_grid->SetFlexibleDirection(wxVERTICAL | wxHORIZONTAL); + + if (titles.size() > 0) { + const size_t odd_items = titles.size() % cols; + + for (size_t i = 0; i < titles.size() - odd_items; i += cols) { + for (size_t j = i; j < i + cols; j++) { printer_grid->Add(titles[j], 0, wxBOTTOM, 3); } + for (size_t j = i; j < i + cols; j++) { printer_grid->Add(bitmaps[j], 0, wxBOTTOM, 20); } + for (size_t j = i; j < i + cols; j++) { printer_grid->Add(variants_panels[j]); } + + // Add separator space + if (i > 0) { + for (size_t j = i; j < i + cols; j++) { printer_grid->Add(1, 100); } + } + } + + if (odd_items > 0) { + for (size_t i = 0; i < cols; i++) { printer_grid->Add(1, 100); } + + const size_t rem = titles.size() - odd_items; + + for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(titles[i], 0, wxBOTTOM, 3); } + for (size_t i = 0; i < cols - odd_items; i++) { printer_grid->AddSpacer(1); } + for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(bitmaps[i], 0, wxBOTTOM, 20); } + for (size_t i = 0; i < cols - odd_items; i++) { printer_grid->AddSpacer(1); } + for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(variants_panels[i]); } + } + } + + auto *title_sizer = new wxBoxSizer(wxHORIZONTAL); + if (! title.IsEmpty()) { + auto *title_widget = new wxStaticText(this, wxID_ANY, title); + title_widget->SetFont(font_title); + title_sizer->Add(title_widget); + } + title_sizer->AddStretchSpacer(); + + if (titles.size() > 1) { + // It only makes sense to add the All / None buttons if there's multiple printers + + auto *sel_all_std = new wxButton(this, wxID_ANY, _(L("All standard"))); + auto *sel_all = new wxButton(this, wxID_ANY, _(L("All"))); + auto *sel_none = new wxButton(this, wxID_ANY, _(L("None"))); + sel_all_std->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(true, false); }); + sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(true, true); }); sel_none->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(false); }); - all_none_sizer->AddStretchSpacer(); - all_none_sizer->Add(sel_all); - all_none_sizer->Add(sel_none); - sizer->AddStretchSpacer(); - sizer->Add(all_none_sizer, 0, wxEXPAND); + title_sizer->Add(sel_all_std, 0, wxRIGHT, BTN_SPACING); + title_sizer->Add(sel_all, 0, wxRIGHT, BTN_SPACING); + title_sizer->Add(sel_none); + } + + sizer->Add(title_sizer, 0, wxEXPAND | wxBOTTOM, BTN_SPACING); + sizer->Add(printer_grid); SetSizer(sizer); } -void PrinterPicker::select_all(bool select) +PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors) + : PrinterPicker(parent, vendor, std::move(title), max_cols, appconfig_vendors, [](const VendorProfile::PrinterModel&) { return true; }) +{} + +void PrinterPicker::select_all(bool select, bool alternates) { for (const auto &cb : cboxes) { if (cb->GetValue() != select) { @@ -135,6 +208,15 @@ void PrinterPicker::select_all(bool select) on_checkbox(cb, select); } } + + if (! select) { alternates = false; } + + for (const auto &cb : cboxes_alt) { + if (cb->GetValue() != alternates) { + cb->SetValue(alternates); + on_checkbox(cb, alternates); +} + } } void PrinterPicker::select_one(size_t i, bool select) @@ -147,7 +229,6 @@ void PrinterPicker::select_one(size_t i, bool select) void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked) { - variants_checked += checked ? 1 : -1; PrinterPickerEvent evt(EVT_PRINTER_PICK, GetId(), vendor_id, cbox->model, cbox->variant, checked); AddPendingEvent(evt); } @@ -155,19 +236,16 @@ void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked) // Wizard page base -ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname) : - wxPanel(parent->p->hscroll), - parent(parent), - shortname(std::move(shortname)), - p_prev(nullptr), - p_next(nullptr) +ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname, unsigned indent) + : wxPanel(parent->p->hscroll) + , parent(parent) + , shortname(std::move(shortname)) + , indent(indent) { auto *sizer = new wxBoxSizer(wxVERTICAL); auto *text = new wxStaticText(this, wxID_ANY, std::move(title), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - auto font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - font.SetWeight(wxFONTWEIGHT_BOLD); - font.SetPointSize(14); + const auto font = GetFont().MakeBold().Scaled(1.5); text->SetFont(font); sizer->Add(text, 0, wxALIGN_LEFT, 0); sizer->AddSpacer(10); @@ -187,18 +265,6 @@ ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxStrin ConfigWizardPage::~ConfigWizardPage() {} -ConfigWizardPage* ConfigWizardPage::chain(ConfigWizardPage *page) -{ - if (p_next != nullptr) { p_next->p_prev = nullptr; } - p_next = page; - if (page != nullptr) { - if (page->p_prev != nullptr) { page->p_prev->p_next = nullptr; } - page->p_prev = this; - } - - return page; -} - void ConfigWizardPage::append_text(wxString text) { auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); @@ -212,22 +278,12 @@ void ConfigWizardPage::append_spacer(int space) content->AddSpacer(space); } -bool ConfigWizardPage::Show(bool show) -{ - if (extra_buttons() != nullptr) { extra_buttons()->Show(show); } - return wxPanel::Show(show); -} - -void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable); } - // Wizard pages -PageWelcome::PageWelcome(ConfigWizard *parent, bool check_first_variant) : - ConfigWizardPage(parent, wxString::Format(_(L("Welcome to the Slic3r %s")), ConfigWizard::name()), _(L("Welcome"))), - printer_picker(nullptr), - others_buttons(new wxPanel(parent)), - cbox_reset(nullptr) +PageWelcome::PageWelcome(ConfigWizard *parent) + : ConfigWizardPage(parent, wxString::Format(_(L("Welcome to the Slic3r %s")), ConfigWizard::name()), _(L("Welcome"))) + , cbox_reset(nullptr) { if (wizard_p()->run_reason == ConfigWizard::RR_DATA_EMPTY) { wxString::Format(_(L("Run %s")), ConfigWizard::name()); @@ -240,57 +296,101 @@ PageWelcome::PageWelcome(ConfigWizard *parent, bool check_first_variant) : append(cbox_reset); } - const auto &vendors = wizard_p()->vendors; - printf("vendors count : %d", vendors.size()); - const auto vendor_prusa = vendors.find(MAIN_VENDOR); + Show(); +} + + +PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortname, const VendorProfile &vendor, unsigned indent, Technology technology) + : ConfigWizardPage(parent, std::move(title), std::move(shortname), indent) +{ + enum { + COL_SIZE = 200, + }; + + bool check_first_variant = wizard_p()->check_first_variant(); - if (vendor_prusa != vendors.cend()) { AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; - printer_picker = new PrinterPicker(this, vendor_prusa->second, appconfig_vendors); + const auto families = vendor.families(); + for (const auto &family : families) { + const auto filter = [&](const VendorProfile::PrinterModel &model) { + return (model.technology == ptFFF && technology & T_FFF + || model.technology == ptSLA && technology & T_SLA) + && model.family == family; + }; + + if (std::find_if(vendor.models.begin(), vendor.models.end(), filter) == vendor.models.end()) { + continue; + } + + const auto picker_title = family.empty() ? wxString() : wxString::Format(_(L("%s Family")), family); + auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, appconfig_vendors, filter); + if (check_first_variant) { // Select the default (first) model/variant on the Prusa vendor - printer_picker->select_one(0, true); + picker->select_one(0, true); + check_first_variant = false; } - printer_picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { + + picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); - this->on_variant_checked(); }); - append(printer_picker); + append(new wxStaticLine(this)); + + append(picker); + printer_pickers.push_back(picker); } - - const size_t num_other_vendors = vendors.size() - (vendor_prusa != vendors.cend()); - auto *sizer = new wxBoxSizer(wxHORIZONTAL); - auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Presets printers"))); - other_vendors->Enable(num_other_vendors > 0); - auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup"))); - - sizer->Add(other_vendors); - sizer->AddSpacer(BTN_SPACING); - sizer->Add(custom_setup); - - other_vendors->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_other_vendors(); }); - custom_setup->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_custom_setup(); }); - - others_buttons->SetSizer(sizer); } -void PageWelcome::on_page_set() +void PagePrinters::select_all(bool select, bool alternates) { - chain(wizard_p()->page_update); - on_variant_checked(); + for (auto picker : printer_pickers) { + picker->select_all(select, alternates); + } } -void PageWelcome::on_variant_checked() +int PagePrinters::get_width() const { - enable_next(printer_picker != nullptr ? printer_picker->variants_checked > 0 : false); + return std::accumulate(printer_pickers.begin(), printer_pickers.end(), 0, + [](int acc, const PrinterPicker *picker) { return std::max(acc, picker->get_width()); }); } -PageUpdate::PageUpdate(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))), - version_check(true), - preset_update(true) + +const char *PageCustom::default_profile_name = "My Settings"; + +PageCustom::PageCustom(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Custom Printer Setup")), _(L("Custom Printer"))) +{ + cb_custom = new wxCheckBox(this, wxID_ANY, _(L("Define a custom printer profile"))); + tc_profile_name = new wxTextCtrl(this, wxID_ANY, default_profile_name); + auto *label = new wxStaticText(this, wxID_ANY, _(L("Custom profile name:"))); + + tc_profile_name->Enable(false); + tc_profile_name->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &evt) { + if (tc_profile_name->GetValue().IsEmpty()) { + if (profile_name_prev.IsEmpty()) { tc_profile_name->SetValue(default_profile_name); } + else { tc_profile_name->SetValue(profile_name_prev); } + } else { + profile_name_prev = tc_profile_name->GetValue(); +} + evt.Skip(); + }); + + cb_custom->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { + tc_profile_name->Enable(custom_wanted()); + wizard_p()->on_custom_setup(custom_wanted()); + }); + + append(cb_custom); + append(label); + append(tc_profile_name); +} + +PageUpdate::PageUpdate(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))) + , version_check(true) + , preset_update(true) { const AppConfig *app_config = GUI::get_app_config(); auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); @@ -318,8 +418,8 @@ PageUpdate::PageUpdate(ConfigWizard *parent) : box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); }); } -PageVendors::PageVendors(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) +PageVendors::PageVendors(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) { append_text(_(L("Pick another vendor supported by Slic3r++:"))); @@ -333,14 +433,13 @@ PageVendors::PageVendors(ConfigWizard *parent) : const auto &vendor = vendor_pair.second; if (vendor.id == MAIN_VENDOR) { continue; } - auto *picker = new PrinterPicker(this, vendor, appconfig_vendors); + auto *picker = new PrinterPicker(this, vendor, "", MAX_COLS, appconfig_vendors); picker->Hide(); pickers.push_back(picker); choices_vendors.Add(vendor.name); picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); - this->on_variant_checked(); }); } @@ -358,31 +457,19 @@ PageVendors::PageVendors(ConfigWizard *parent) : for (PrinterPicker *picker : pickers) { this->append(picker); } } -void PageVendors::on_page_set() -{ - on_variant_checked(); -} - void PageVendors::on_vendor_pick(size_t i) { for (PrinterPicker *picker : pickers) { picker->Hide(); } if (i < pickers.size()) { pickers[i]->Show(); - wizard_p()->layout_fit(); + parent->Layout(); } } -void PageVendors::on_variant_checked() -{ - size_t variants_checked = 0; - for (const PrinterPicker *picker : pickers) { variants_checked += picker->variants_checked; } - enable_next(variants_checked > 0); -} - -PageFirmware::PageFirmware(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))), - gcode_opt(*print_config_def.get("gcode_flavor")), - gcode_picker(nullptr) +PageFirmware::PageFirmware(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware")), 1) + , gcode_opt(*print_config_def.get("gcode_flavor")) + , gcode_picker(nullptr) { append_text(_(L("Choose the type of firmware used by your printer."))); append_text(gcode_opt.tooltip); @@ -411,15 +498,15 @@ PageFirmware::PageFirmware(ConfigWizard *parent) : void PageFirmware::apply_custom_config(DynamicPrintConfig &config) { auto sel = gcode_picker->GetSelection(); - if (sel >= 0 && sel < gcode_opt.enum_labels.size()) { + if (sel >= 0 && (size_t)sel < gcode_opt.enum_labels.size()) { auto *opt = new ConfigOptionEnum(static_cast(sel)); config.set_key_value("gcode_flavor", opt); } } -PageBedShape::PageBedShape(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Bed Shape and Size")), _(L("Bed Shape"))), - shape_panel(new BedShapePanel(this)) +PageBedShape::PageBedShape(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Bed Shape and Size")), _(L("Bed Shape")), 1) + , shape_panel(new BedShapePanel(this)) { append_text(_(L("Set the shape of your printer's bed."))); @@ -434,10 +521,10 @@ void PageBedShape::apply_custom_config(DynamicPrintConfig &config) config.set_key_value("bed_shape", opt); } -PageDiameters::PageDiameters(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Filament and Nozzle Diameters")), _(L("Print Diameters"))), - spin_nozzle(new wxSpinCtrlDouble(this, wxID_ANY)), - spin_filam(new wxSpinCtrlDouble(this, wxID_ANY)) +PageDiameters::PageDiameters(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Filament and Nozzle Diameters")), _(L("Print Diameters")), 1) + , spin_nozzle(new wxSpinCtrlDouble(this, wxID_ANY)) + , spin_filam(new wxSpinCtrlDouble(this, wxID_ANY)) { spin_nozzle->SetDigits(2); spin_nozzle->SetIncrement(0.1); @@ -485,10 +572,10 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) config.set_key_value("filament_diameter", opt_filam); } -PageTemperatures::PageTemperatures(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Extruder and Bed Temperatures")), _(L("Temperatures"))), - spin_extr(new wxSpinCtrlDouble(this, wxID_ANY)), - spin_bed(new wxSpinCtrlDouble(this, wxID_ANY)) +PageTemperatures::PageTemperatures(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("Extruder and Bed Temperatures")), _(L("Temperatures")), 1) + , spin_extr(new wxSpinCtrlDouble(this, wxID_ANY)) + , spin_bed(new wxSpinCtrlDouble(this, wxID_ANY)) { spin_extr->SetIncrement(5.0); const auto &def_extr = *print_config_def.get("temperature"); @@ -544,17 +631,21 @@ void PageTemperatures::apply_custom_config(DynamicPrintConfig &config) // Index -ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) : - wxPanel(parent), - bg(GUI::from_u8(Slic3r::var("Slic3r_192px_transparent.png")), wxBITMAP_TYPE_PNG), - bullet_black(GUI::from_u8(Slic3r::var("bullet_black.png")), wxBITMAP_TYPE_PNG), - bullet_blue(GUI::from_u8(Slic3r::var("bullet_blue.png")), wxBITMAP_TYPE_PNG), - bullet_white(GUI::from_u8(Slic3r::var("bullet_white.png")), wxBITMAP_TYPE_PNG) +ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) + : wxPanel(parent) + , bg(GUI::from_u8(Slic3r::var("Slic3r_192px_transparent.png")), wxBITMAP_TYPE_PNG) + , bullet_black(GUI::from_u8(Slic3r::var("bullet_black.png")), wxBITMAP_TYPE_PNG) + , bullet_blue(GUI::from_u8(Slic3r::var("bullet_blue.png")), wxBITMAP_TYPE_PNG) + , bullet_white(GUI::from_u8(Slic3r::var("bullet_white.png")), wxBITMAP_TYPE_PNG) + , item_active(0) + , item_hover(-1) + , last_page((size_t)-1) { SetMinSize(bg.GetSize()); - wxClientDC dc(this); - text_height = dc.GetCharHeight(); + const wxSize size = GetTextExtent("m"); + em = size.x; + em_h = size.y; // Add logo bitmap. // This could be done in on_paint() along with the index labels, but I've found it tricky @@ -568,33 +659,103 @@ ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) : SetSizer(sizer); Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this); + Bind(wxEVT_MOTION, &ConfigWizardIndex::on_mouse_move, this); + + Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &evt) { + if (item_hover != -1) { + item_hover = -1; + Refresh(); +} + evt.Skip(); + }); + + Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &evt) { + if (item_hover >= 0) { go_to(item_hover); } + }); } -void ConfigWizardIndex::load_items(ConfigWizardPage *firstpage) -{ - items.clear(); - item_active = items.cend(); +wxDECLARE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); - for (auto *page = firstpage; page != nullptr; page = page->page_next()) { - items.emplace_back(page->shortname); +void ConfigWizardIndex::add_page(ConfigWizardPage *page) +{ + last_page = items.size(); + items.emplace_back(Item { page->shortname, page->indent, page }); + Refresh(); } +void ConfigWizardIndex::add_label(wxString label, unsigned indent) +{ + items.emplace_back(Item { std::move(label), indent, nullptr }); Refresh(); } -void ConfigWizardIndex::set_active(ConfigWizardPage *page) +ConfigWizardPage* ConfigWizardIndex::active_page() const { - item_active = std::find(items.cbegin(), items.cend(), page->shortname); + if (item_active >= items.size()) { return nullptr; } + + return items[item_active].page; +} + +void ConfigWizardIndex::go_prev() +{ + // Search for a preceiding item that is a page (not a label, ie. page != nullptr) + + for (size_t i = item_active; i > 0; i--) { + if (items[i - 1].page != nullptr) { + go_to(i - 1); + return; + } + } +} + +void ConfigWizardIndex::go_next() +{ + // Search for a next item that is a page (not a label, ie. page != nullptr) + + for (size_t i = item_active + 1; i < items.size(); i++) { + if (items[i].page != nullptr) { + go_to(i); + return; + } + } +} + +void ConfigWizardIndex::go_to(size_t i) +{ + if (i < items.size() && items[i].page != nullptr) { + auto *former_active = active_page(); + if (former_active != nullptr) { former_active->Hide(); } + + item_active = i; + items[i].page->Show(); + + wxCommandEvent evt(EVT_INDEX_PAGE, GetId()); + AddPendingEvent(evt); + Refresh(); } +} + +void ConfigWizardIndex::go_to(ConfigWizardPage *page) +{ + if (page == nullptr) { return; } + + for (size_t i = 0; i < items.size(); i++) { + if (items[i].page == page) { go_to(i); } + } +} + +void ConfigWizardIndex::clear() +{ + auto *former_active = active_page(); + if (former_active != nullptr) { former_active->Hide(); } + + items.clear(); + item_active = 0; +} void ConfigWizardIndex::on_paint(wxPaintEvent & evt) { - enum { - MARGIN = 10, - SPACING = 5, - }; - const auto size = GetClientSize(); if (size.GetHeight() == 0 || size.GetWidth() == 0) { return; } @@ -602,20 +763,40 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt) const auto bullet_w = bullet_black.GetSize().GetWidth(); const auto bullet_h = bullet_black.GetSize().GetHeight(); - const int yoff_icon = bullet_h < text_height ? (text_height - bullet_h) / 2 : 0; - const int yoff_text = bullet_h > text_height ? (bullet_h - text_height) / 2 : 0; - const int yinc = std::max(bullet_h, text_height) + SPACING; + const int yoff_icon = bullet_h < em_h ? (em_h - bullet_h) / 2 : 0; + const int yoff_text = bullet_h > em_h ? (bullet_h - em_h) / 2 : 0; + const int yinc = item_height(); unsigned y = 0; - for (auto it = items.cbegin(); it != items.cend(); ++it) { - if (it < item_active) { dc.DrawBitmap(bullet_black, MARGIN, y + yoff_icon, false); } - if (it == item_active) { dc.DrawBitmap(bullet_blue, MARGIN, y + yoff_icon, false); } - if (it > item_active) { dc.DrawBitmap(bullet_white, MARGIN, y + yoff_icon, false); } - dc.DrawText(*it, MARGIN + bullet_w + SPACING, y + yoff_text); + for (size_t i = 0; i < items.size(); i++) { + const Item& item = items[i]; + unsigned x = em/2 + item.indent * em; + + if (i == item_active || item_hover >= 0 && i == (size_t)item_hover) { + dc.DrawBitmap(bullet_blue, x, y + yoff_icon, false); + } + else if (i < item_active) { dc.DrawBitmap(bullet_black, x, y + yoff_icon, false); } + else if (i > item_active) { dc.DrawBitmap(bullet_white, x, y + yoff_icon, false); } + + dc.DrawText(item.label, x + bullet_w + em/2, y + yoff_text); y += yinc; } } +void ConfigWizardIndex::on_mouse_move(wxMouseEvent &evt) +{ + const wxClientDC dc(this); + const wxPoint pos = evt.GetLogicalPosition(dc); + + const ssize_t item_hover_new = pos.y / item_height(); + + if (item_hover_new < ssize_t(items.size()) && item_hover_new != item_hover) { + item_hover = item_hover_new; + Refresh(); + } + + evt.Skip(); +} // priv @@ -631,6 +812,36 @@ static const std::unordered_map { "Original Prusa i3 MK3.ini", std::make_pair("MK3", "0.4") }, }}; +void ConfigWizard::priv::load_pages(bool custom_setup) +{ + const auto former_active = index->active_item(); + + index->clear(); + + index->add_page(page_welcome); + index->add_page(page_fff); + index->add_page(page_msla); + index->add_page(page_custom); + + if (custom_setup) { + index->add_page(page_firmware); + index->add_page(page_bed); + index->add_page(page_diams); + index->add_page(page_temps); + } + + index->add_page(page_update); + + index->go_to(former_active); // Will restore the active item/page if possible + + q->Layout(); +} + +bool ConfigWizard::priv::check_first_variant() const +{ + return run_reason == RR_DATA_EMPTY || run_reason == RR_DATA_LEGACY; +} + void ConfigWizard::priv::load_vendors() { const fs::path vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; @@ -676,53 +887,17 @@ void ConfigWizard::priv::load_vendors() auto needle = legacy_preset_map.find(dir_entry.path().filename().string()); if (needle == legacy_preset_map.end()) { continue; } - const auto &model = needle->second.first; - const auto &variant = needle->second.second; - appconfig_vendors.set_variant(MAIN_VENDOR, model, variant, true); - } + const auto &model = needle->second.first; + const auto &variant = needle->second.second; + appconfig_vendors.set_variant("PrusaResearch", model, variant, true); + } } } -void ConfigWizard::priv::index_refresh() -{ - index->load_items(page_welcome); -} - void ConfigWizard::priv::add_page(ConfigWizardPage *page) { hscroll_sizer->Add(page, 0, wxEXPAND); - - auto *extra_buttons = page->extra_buttons(); - if (extra_buttons != nullptr) { - btnsizer->Prepend(extra_buttons, 0); } -} - -void ConfigWizard::priv::set_page(ConfigWizardPage *page) -{ - if (page == nullptr) { return; } - if (page_current != nullptr) { page_current->Hide(); } - page_current = page; - enable_next(true); - - page->on_page_set(); - index->load_items(page_welcome); - index->set_active(page); - page->Show(); - - btn_prev->Enable(page->page_prev() != nullptr); - btn_next->Show(page->page_next() != nullptr); - btn_finish->Show(page->page_next() == nullptr); - - layout_fit(); -} - -void ConfigWizard::priv::layout_fit() -{ - q->Layout(); - q->Fit(); - q->SetSize(wxRect(0, 0, 1200, 700)); -} void ConfigWizard::priv::enable_next(bool enable) { @@ -730,26 +905,13 @@ void ConfigWizard::priv::enable_next(bool enable) btn_finish->Enable(enable); } -void ConfigWizard::priv::on_other_vendors() +void ConfigWizard::priv::on_custom_setup(bool custom_wanted) { - page_welcome - ->chain(page_vendors) - ->chain(page_update); - set_page(page_vendors); -} - -void ConfigWizard::priv::on_custom_setup() -{ - page_welcome->chain(page_firmware); - page_temps->chain(page_update); - set_page(page_firmware); + load_pages(custom_wanted); } void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater) { - const bool is_custom_setup = page_welcome->page_next() == page_firmware; - - if (! is_custom_setup) { const auto enabled_vendors = appconfig_vendors.vendors(); // Install bundles from resources if needed: @@ -791,21 +953,27 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese app_config->set("preset_update", page_update->preset_update ? "1" : "0"); app_config->reset_selections(); preset_bundle->load_presets(*app_config); - } else { - for (ConfigWizardPage *page = page_firmware; page != nullptr; page = page->page_next()) { - page->apply_custom_config(*custom_config); + + + if (page_custom->custom_wanted()) { + page_firmware->apply_custom_config(*custom_config); + page_bed->apply_custom_config(*custom_config); + page_diams->apply_custom_config(*custom_config); + page_temps->apply_custom_config(*custom_config); + + const std::string profile_name = page_custom->profile_name(); + preset_bundle->load_config(profile_name, *custom_config); } - preset_bundle->load_config("My Settings", *custom_config); - } + // Update the selections from the compatibilty. preset_bundle->export_selections(*app_config); } // Public -ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) : - wxDialog(parent, wxID_ANY, _(name().ToStdString()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - p(new priv(this)) +ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) + : wxDialog(parent, wxID_ANY, _(name().ToStdString()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + , p(new priv(this)) { p->run_reason = reason; @@ -831,55 +999,92 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) : topsizer->AddSpacer(INDEX_MARGIN); topsizer->Add(p->hscroll, 1, wxEXPAND); + auto *btn_sel_all = new wxButton(this, wxID_ANY, _(L("Select all standard printers"))); + p->btnsizer->Add(btn_sel_all); + p->btn_prev = new wxButton(this, wxID_ANY, _(L("< &Back"))); p->btn_next = new wxButton(this, wxID_ANY, _(L("&Next >"))); 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, _(L("Cancel"))); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac p->btnsizer->AddStretchSpacer(); p->btnsizer->Add(p->btn_prev, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_next, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING); - p->add_page(p->page_welcome = new PageWelcome(this, reason == RR_DATA_EMPTY || reason == RR_DATA_LEGACY)); + const auto &vendors = p->vendors; + const auto vendor_prusa_it = vendors.find("PrusaResearch"); + wxCHECK_RET(vendor_prusa_it != vendors.cend(), "Vendor PrusaResearch not found"); + const VendorProfile &vendor_prusa = vendor_prusa_it->second; + + p->add_page(p->page_welcome = new PageWelcome(this)); + + p->page_fff = new PagePrinters(this, _(L("Prusa FFF Technology Printers")), "Prusa FFF", vendor_prusa, 0, PagePrinters::T_FFF); + p->add_page(p->page_fff); + + p->page_msla = new PagePrinters(this, _(L("Prusa MSLA Technology Printers")), "Prusa MSLA", vendor_prusa, 0, PagePrinters::T_SLA); + p->add_page(p->page_msla); + + p->add_page(p->page_custom = new PageCustom(this)); p->add_page(p->page_update = new PageUpdate(this)); p->add_page(p->page_vendors = new PageVendors(this)); p->add_page(p->page_firmware = new PageFirmware(this)); p->add_page(p->page_bed = new PageBedShape(this)); p->add_page(p->page_diams = new PageDiameters(this)); p->add_page(p->page_temps = new PageTemperatures(this)); - p->index_refresh(); - p->page_welcome->chain(p->page_update); - p->page_firmware - ->chain(p->page_bed) - ->chain(p->page_diams) - ->chain(p->page_temps); + p->load_pages(false); vsizer->Add(topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); vsizer->Add(hline, 0, wxEXPAND); vsizer->Add(p->btnsizer, 0, wxEXPAND | wxALL, DIALOG_MARGIN); - p->set_page(p->page_welcome); SetSizer(vsizer); SetSizerAndFit(vsizer); // We can now enable scrolling on hscroll p->hscroll->SetScrollRate(30, 30); - // Compare current ("ideal") wizard size with the size of the current screen. - // If the screen is smaller, resize wizrad to match, which will enable scrollbars. - auto wizard_size = GetSize(); - unsigned width, height; - if (GUI::get_current_screen_size(this, width, height)) { - wizard_size.SetWidth(std::min(wizard_size.GetWidth(), (int)(width - 2 * DIALOG_MARGIN))); - wizard_size.SetHeight(std::min(wizard_size.GetHeight(), (int)(height - 2 * DIALOG_MARGIN))); - SetMinSize(wizard_size); - } - Fit(); - p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); - p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); }); - p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->EndModal(wxID_OK); }); + on_window_geometry(this, [this]() { + // Clamp the Wizard size based on screen dimensions + + const auto idx = wxDisplay::GetFromWindow(this); + wxDisplay display(idx != wxNOT_FOUND ? idx : 0u); + + const auto disp_rect = display.GetClientArea(); + wxRect window_rect( + disp_rect.x + disp_rect.width / 20, + disp_rect.y + disp_rect.height / 20, + 9*disp_rect.width / 10, + 9*disp_rect.height / 10); + + const int width_hint = p->index->GetSize().GetWidth() + p->page_fff->get_width() + 300; // XXX: magic constant, I found no better solution + if (width_hint < window_rect.width) { + window_rect.x += (window_rect.width - width_hint) / 2; + window_rect.width = width_hint; + } + + SetSize(window_rect); + }); + + p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { this->p->index->go_prev(); }); + p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { this->p->index->go_next(); }); + p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { this->EndModal(wxID_OK); }); + p->btn_finish->Hide(); + + btn_sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { + p->page_fff->select_all(true, false); + p->page_msla->select_all(true, false); + p->index->go_to(p->page_update); + }); + + p->index->Bind(EVT_INDEX_PAGE, [this](const wxCommandEvent &) { + const bool is_last = p->index->active_is_last(); + p->btn_next->Show(! is_last); + p->btn_finish->Show(is_last); + + Layout(); + }); } ConfigWizard::~ConfigWizard() {} diff --git a/src/slic3r/GUI/ConfigWizard.hpp b/src/slic3r/GUI/ConfigWizard.hpp index c7fba76ee..c9ee05529 100644 --- a/src/slic3r/GUI/ConfigWizard.hpp +++ b/src/slic3r/GUI/ConfigWizard.hpp @@ -16,30 +16,30 @@ namespace GUI { class ConfigWizard: public wxDialog { public: - // Why is the Wizard run - enum RunReason { - RR_DATA_EMPTY, // No or empty datadir - RR_DATA_LEGACY, // Pre-updating datadir - RR_DATA_INCOMPAT, // Incompatible datadir - Slic3r downgrade situation - RR_USER, // User requested the Wizard from the menus - }; + // Why is the Wizard run + enum RunReason { + RR_DATA_EMPTY, // No or empty datadir + RR_DATA_LEGACY, // Pre-updating datadir + RR_DATA_INCOMPAT, // Incompatible datadir - Slic3r downgrade situation + RR_USER, // User requested the Wizard from the menus + }; - ConfigWizard(wxWindow *parent, RunReason run_reason); - ConfigWizard(ConfigWizard &&) = delete; - ConfigWizard(const ConfigWizard &) = delete; - ConfigWizard &operator=(ConfigWizard &&) = delete; - ConfigWizard &operator=(const ConfigWizard &) = delete; - ~ConfigWizard(); + ConfigWizard(wxWindow *parent, RunReason run_reason); + ConfigWizard(ConfigWizard &&) = delete; + ConfigWizard(const ConfigWizard &) = delete; + ConfigWizard &operator=(ConfigWizard &&) = delete; + ConfigWizard &operator=(const ConfigWizard &) = delete; + ~ConfigWizard(); - // Run the Wizard. Return whether it was completed. - bool run(PresetBundle *preset_bundle, const PresetUpdater *updater); + // Run the Wizard. Return whether it was completed. + bool run(PresetBundle *preset_bundle, const PresetUpdater *updater); - static const wxString& name(const bool from_menu = false); + static const wxString& name(const bool from_menu = false); private: - struct priv; - std::unique_ptr p; + struct priv; + std::unique_ptr p; - friend struct ConfigWizardPage; + friend struct ConfigWizardPage; }; diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 2c8f23cd3..df7602adf 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include "libslic3r/PrintConfig.hpp" #include "slic3r/Utils/PresetUpdater.hpp" @@ -26,211 +28,264 @@ namespace Slic3r { namespace GUI { enum { - WRAP_WIDTH = 500, - MODEL_MIN_WRAP = 150, + WRAP_WIDTH = 500, + MODEL_MIN_WRAP = 150, - DIALOG_MARGIN = 15, - INDEX_MARGIN = 40, - BTN_SPACING = 10, - INDENT_SPACING = 30, - VERTICAL_SPACING = 10, + DIALOG_MARGIN = 15, + INDEX_MARGIN = 40, + BTN_SPACING = 10, + INDENT_SPACING = 30, + VERTICAL_SPACING = 10, + + MAX_COLS = 4, + ROW_SPACING = 75, }; +typedef std::function ModelFilter; + struct PrinterPicker: wxPanel { - struct Checkbox : wxCheckBox - { - Checkbox(wxWindow *parent, const wxString &label, const std::string &model, const std::string &variant) : - wxCheckBox(parent, wxID_ANY, label), - model(model), - variant(variant) - {} + struct Checkbox : wxCheckBox + { + Checkbox(wxWindow *parent, const wxString &label, const std::string &model, const std::string &variant) : + wxCheckBox(parent, wxID_ANY, label), + model(model), + variant(variant) + {} - std::string model; - std::string variant; - }; + std::string model; + std::string variant; + }; - const std::string vendor_id; - std::vector cboxes; - unsigned variants_checked; + const std::string vendor_id; + std::vector cboxes; + std::vector cboxes_alt; - PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors); + PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors, const ModelFilter &filter); + PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors); - void select_all(bool select); - void select_one(size_t i, bool select); - void on_checkbox(const Checkbox *cbox, bool checked); + void select_all(bool select, bool alternates = false); + void select_one(size_t i, bool select); + void on_checkbox(const Checkbox *cbox, bool checked); + + int get_width() const { return width; } +private: + int width; }; struct ConfigWizardPage: wxPanel { - ConfigWizard *parent; - const wxString shortname; - wxBoxSizer *content; + ConfigWizard *parent; + const wxString shortname; + wxBoxSizer *content; + const unsigned indent; - ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname); + ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname, unsigned indent = 0); + virtual ~ConfigWizardPage(); - virtual ~ConfigWizardPage(); + template + void append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) + { + content->Add(thing, proportion, flag, border); + } - ConfigWizardPage* page_prev() const { return p_prev; } - ConfigWizardPage* page_next() const { return p_next; } - ConfigWizardPage* chain(ConfigWizardPage *page); + void append_text(wxString text); + void append_spacer(int space); - template - void append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) - { - content->Add(thing, proportion, flag, border); - } + ConfigWizard::priv *wizard_p() const { return parent->p.get(); } - void append_text(wxString text); - void append_spacer(int space); - - ConfigWizard::priv *wizard_p() const { return parent->p.get(); } - - virtual bool Show(bool show = true); - virtual bool Hide() { return Show(false); } - virtual wxPanel* extra_buttons() { return nullptr; } - virtual void on_page_set() {} - virtual void apply_custom_config(DynamicPrintConfig &config) {} - - void enable_next(bool enable); -private: - ConfigWizardPage *p_prev; - ConfigWizardPage *p_next; + virtual void apply_custom_config(DynamicPrintConfig &config) {} }; struct PageWelcome: ConfigWizardPage { - PrinterPicker *printer_picker; - wxPanel *others_buttons; - wxCheckBox *cbox_reset; + wxCheckBox *cbox_reset; - PageWelcome(ConfigWizard *parent, bool check_first_variant); + PageWelcome(ConfigWizard *parent); - virtual wxPanel* extra_buttons() { return others_buttons; } - virtual void on_page_set(); + bool reset_user_profile() const { return cbox_reset != nullptr ? cbox_reset->GetValue() : false; } +}; + +struct PagePrinters: ConfigWizardPage +{ + enum Technology { + // Bitflag equivalent of PrinterTechnology + T_FFF = 0x1, + T_SLA = 0x2, + T_Any = ~0, + }; + + std::vector printer_pickers; + + PagePrinters(ConfigWizard *parent, wxString title, wxString shortname, const VendorProfile &vendor, unsigned indent, Technology technology); + + void select_all(bool select, bool alternates = false); + int get_width() const; +}; + +struct PageCustom: ConfigWizardPage +{ + PageCustom(ConfigWizard *parent); + + bool custom_wanted() const { return cb_custom->GetValue(); } + std::string profile_name() const { return into_u8(tc_profile_name->GetValue()); } + +private: + static const char* default_profile_name; + + wxCheckBox *cb_custom; + wxTextCtrl *tc_profile_name; + wxString profile_name_prev; - bool reset_user_profile() const { return cbox_reset != nullptr ? cbox_reset->GetValue() : false; } - void on_variant_checked(); }; struct PageUpdate: ConfigWizardPage { - bool version_check; - bool preset_update; + bool version_check; + bool preset_update; - PageUpdate(ConfigWizard *parent); + PageUpdate(ConfigWizard *parent); }; struct PageVendors: ConfigWizardPage { - std::vector pickers; + std::vector pickers; - PageVendors(ConfigWizard *parent); + PageVendors(ConfigWizard *parent); - virtual void on_page_set(); - - void on_vendor_pick(size_t i); - void on_variant_checked(); + void on_vendor_pick(size_t i); }; struct PageFirmware: ConfigWizardPage { - const ConfigOptionDef &gcode_opt; - wxChoice *gcode_picker; + const ConfigOptionDef &gcode_opt; + wxChoice *gcode_picker; - PageFirmware(ConfigWizard *parent); - virtual void apply_custom_config(DynamicPrintConfig &config); + PageFirmware(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; struct PageBedShape: ConfigWizardPage { - BedShapePanel *shape_panel; + BedShapePanel *shape_panel; - PageBedShape(ConfigWizard *parent); - virtual void apply_custom_config(DynamicPrintConfig &config); + PageBedShape(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; struct PageDiameters: ConfigWizardPage { - wxSpinCtrlDouble *spin_nozzle; - wxSpinCtrlDouble *spin_filam; + wxSpinCtrlDouble *spin_nozzle; + wxSpinCtrlDouble *spin_filam; - PageDiameters(ConfigWizard *parent); - virtual void apply_custom_config(DynamicPrintConfig &config); + PageDiameters(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; struct PageTemperatures: ConfigWizardPage { - wxSpinCtrlDouble *spin_extr; - wxSpinCtrlDouble *spin_bed; + wxSpinCtrlDouble *spin_extr; + wxSpinCtrlDouble *spin_bed; - PageTemperatures(ConfigWizard *parent); - virtual void apply_custom_config(DynamicPrintConfig &config); + PageTemperatures(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; class ConfigWizardIndex: public wxPanel { public: - ConfigWizardIndex(wxWindow *parent); + ConfigWizardIndex(wxWindow *parent); + + void add_page(ConfigWizardPage *page); + void add_label(wxString label, unsigned indent = 0); + + size_t active_item() const { return item_active; } + ConfigWizardPage* active_page() const; + bool active_is_last() const { return item_active < items.size() && item_active == last_page; } + + void go_prev(); + void go_next(); + void go_to(size_t i); + void go_to(ConfigWizardPage *page); + + void clear(); - void load_items(ConfigWizardPage *firstpage); - void set_active(ConfigWizardPage *page); private: - const wxBitmap bg; - const wxBitmap bullet_black; - const wxBitmap bullet_blue; - const wxBitmap bullet_white; - int text_height; + struct Item + { + wxString label; + unsigned indent; + ConfigWizardPage *page; // nullptr page => label-only item - std::vector items; - std::vector::const_iterator item_active; + bool operator==(ConfigWizardPage *page) const { return this->page == page; } + }; - void on_paint(wxPaintEvent &evt); + int em; + int em_h; + + const wxBitmap bg; + const wxBitmap bullet_black; + const wxBitmap bullet_blue; + const wxBitmap bullet_white; + + std::vector items; + size_t item_active; + ssize_t item_hover; + size_t last_page; + + int item_height() const { return std::max(bullet_black.GetSize().GetHeight(), em) + em; } + + void on_paint(wxPaintEvent &evt); + void on_mouse_move(wxMouseEvent &evt); }; +wxDEFINE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); + struct ConfigWizard::priv { - ConfigWizard *q; - ConfigWizard::RunReason run_reason; - AppConfig appconfig_vendors; - std::unordered_map vendors; - std::unordered_map vendors_rsrc; - std::unique_ptr custom_config; + ConfigWizard *q; + ConfigWizard::RunReason run_reason; + AppConfig appconfig_vendors; + std::unordered_map vendors; + std::unordered_map vendors_rsrc; + std::unique_ptr custom_config; - wxScrolledWindow *hscroll = nullptr; - wxBoxSizer *hscroll_sizer = nullptr; - wxBoxSizer *btnsizer = nullptr; - ConfigWizardPage *page_current = nullptr; - ConfigWizardIndex *index = nullptr; - wxButton *btn_prev = nullptr; - wxButton *btn_next = nullptr; - wxButton *btn_finish = nullptr; - wxButton *btn_cancel = nullptr; + wxScrolledWindow *hscroll = nullptr; + wxBoxSizer *hscroll_sizer = nullptr; + wxBoxSizer *btnsizer = nullptr; + ConfigWizardPage *page_current = nullptr; + ConfigWizardIndex *index = nullptr; + wxButton *btn_prev = nullptr; + wxButton *btn_next = nullptr; + wxButton *btn_finish = nullptr; + wxButton *btn_cancel = nullptr; - PageWelcome *page_welcome = nullptr; - PageUpdate *page_update = nullptr; - PageVendors *page_vendors = nullptr; - PageFirmware *page_firmware = nullptr; - PageBedShape *page_bed = nullptr; - PageDiameters *page_diams = nullptr; - PageTemperatures *page_temps = nullptr; + PageWelcome *page_welcome = nullptr; + PagePrinters *page_fff = nullptr; + PagePrinters *page_msla = nullptr; + PageCustom *page_custom = nullptr; + PageUpdate *page_update = nullptr; + PageVendors *page_vendors = nullptr; // XXX: ? - priv(ConfigWizard *q) : q(q) {} + // Custom setup pages + PageFirmware *page_firmware = nullptr; + PageBedShape *page_bed = nullptr; + PageDiameters *page_diams = nullptr; + PageTemperatures *page_temps = nullptr; - void load_vendors(); - void add_page(ConfigWizardPage *page); - void index_refresh(); - void set_page(ConfigWizardPage *page); - void layout_fit(); - void go_prev() { if (page_current != nullptr) { set_page(page_current->page_prev()); } } - void go_next() { if (page_current != nullptr) { set_page(page_current->page_next()); } } - void enable_next(bool enable); + priv(ConfigWizard *q) : q(q) {} - void on_other_vendors(); - void on_custom_setup(); + void load_pages(bool custom_setup); - void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); + bool check_first_variant() const; + void load_vendors(); + void add_page(ConfigWizardPage *page); + void enable_next(bool enable); + + void on_custom_setup(bool custom_wanted); + + void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); }; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index e74e0f01c..a17d6c805 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -631,14 +631,19 @@ void Choice::set_value(const boost::any& value, bool change_event) break; ++idx; } - idx == m_opt.enum_values.size() ? - dynamic_cast(window)->SetValue(text_value) : + if (idx == m_opt.enum_values.size()) { + // For editable Combobox under OSX is needed to set selection to -1 explicitly, + // otherwise selection doesn't be changed + dynamic_cast(window)->SetSelection(-1); + dynamic_cast(window)->SetValue(text_value); + } + else dynamic_cast(window)->SetSelection(idx); break; } case coEnum: { int val = boost::any_cast(value); - if (m_opt_id.compare("top_fill_pattern") == 0 || m_opt_id.compare("bottom_fill_pattern") == 0 || m_opt_id.compare("solid_fill_pattern") == 0) + if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "solid_fill_pattern") { if (!m_opt.enum_values.empty()) { std::string key; @@ -728,8 +733,7 @@ boost::any& Choice::get_value() if (m_opt.type == coEnum) { int ret_enum = static_cast(window)->GetSelection(); - if (m_opt_id.compare("top_fill_pattern") == 0 || m_opt_id.compare("bottom_fill_pattern") == 0 - || m_opt_id.compare("solid_fill_pattern") == 0 || m_opt_id.compare("support_material_interface_pattern") == 0) + if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "solid_fill_pattern" || m_opt_id == "support_material_interface_pattern") { if (!m_opt.enum_values.empty()) { std::string key = m_opt.enum_values[ret_enum]; @@ -823,14 +827,9 @@ boost::any& ColourPicker::get_value() void PointCtrl::BUILD() { - auto size = wxSize(wxDefaultSize); - if (m_opt.height >= 0) size.SetHeight(m_opt.height); - if (m_opt.width >= 0) size.SetWidth(m_opt.width); - auto temp = new wxBoxSizer(wxHORIZONTAL); - // $self->wxSizer($sizer); - // - wxSize field_size(40, -1); + + const wxSize field_size(4 * wxGetApp().em_unit(), -1); auto default_pt = static_cast(m_opt.default_value)->values.at(0); double val = default_pt(0); diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 2df1f0bc9..1a294d210 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -13,6 +13,7 @@ #include "libslic3r/Utils.hpp" #include "avrdude/avrdude-slic3r.hpp" #include "GUI.hpp" +#include "GUI_App.hpp" #include "I18N.hpp" #include "MsgDialog.hpp" #include "../Utils/HexFile.hpp" @@ -36,7 +37,6 @@ #include #include #include -#include "GUI_App.hpp" namespace fs = boost::filesystem; @@ -122,7 +122,6 @@ struct FirmwareDialog::priv // 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). AvrDude::Ptr avrdude; - std::string avrdude_config; unsigned progress_tasks_done; unsigned progress_tasks_bar; bool user_cancelled; @@ -134,7 +133,6 @@ struct FirmwareDialog::priv btn_flash_label_flashing(_(L("Cancel"))), label_status_flashing(_(L("Flashing in progress. Please do not disconnect the printer!"))), timer_pulse(q), - avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()), progress_tasks_done(0), progress_tasks_bar(0), user_cancelled(false), @@ -446,7 +444,7 @@ void FirmwareDialog::priv::prepare_common() "-U", (boost::format("flash:w:0:%1%:i") % hex_file.path.string()).str(), }}; - BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: " + BOOST_LOG_TRIVIAL(info) << "Preparing arguments avrdude: " << std::accumulate(std::next(args.begin()), args.end(), args[0], [](std::string a, const std::string &b) { return a + ' ' + b; }); @@ -492,7 +490,7 @@ void FirmwareDialog::priv::prepare_mk3() "-U", (boost::format("flash:w:1:%1%:i") % hex_file.path.string()).str(), }}; - BOOST_LOG_TRIVIAL(info) << "Invoking avrdude for external flash flashing, arguments: " + BOOST_LOG_TRIVIAL(info) << "Preparing avrdude arguments for external flash flashing: " << std::accumulate(std::next(args.begin()), args.end(), args[0], [](std::string a, const std::string &b) { return a + ' ' + b; }); @@ -522,7 +520,7 @@ void FirmwareDialog::priv::prepare_mm_control() "-U", (boost::format("flash:w:0:%1%:i") % hex_file.path.string()).str(), }}; - BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: " + BOOST_LOG_TRIVIAL(info) << "Preparing avrdude arguments: " << std::accumulate(std::next(args.begin()), args.end(), args[0], [](std::string a, const std::string &b) { return a + ' ' + b; }); @@ -553,7 +551,7 @@ void FirmwareDialog::priv::perform_upload() flashing_start(hex_file.device == HexFile::DEV_MK3 ? 2 : 1); // Init the avrdude object - AvrDude avrdude(avrdude_config); + AvrDude avrdude; // 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. @@ -588,6 +586,13 @@ void FirmwareDialog::priv::perform_upload() auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId()); auto wxmsg = wxString::FromUTF8(msg); +#ifdef WIN32 + // The string might be in local encoding + if (wxmsg.IsEmpty() && *msg != '\0') { + wxmsg = wxString(msg); + } +#endif + evt->SetExtraLong(AE_MESSAGE); evt->SetString(std::move(wxmsg)); wxQueueEvent(q, evt); @@ -693,11 +698,16 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : enum { DIALOG_MARGIN = 15, SPACING = 10, - MIN_WIDTH = 600, - MIN_HEIGHT = 200, - MIN_HEIGHT_EXPANDED = 500, + MIN_WIDTH = 50, + MIN_HEIGHT = 18, + MIN_HEIGHT_EXPANDED = 40, }; + const int em = GUI::wxGetApp().em_unit(); + int min_width = MIN_WIDTH * em; + int min_height = MIN_HEIGHT * em; + int min_height_expanded = MIN_HEIGHT_EXPANDED * em; + wxFont status_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); status_font.MakeBold(); wxFont mono_font(wxFontInfo().Family(wxFONTFAMILY_TELETYPE)); @@ -710,7 +720,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : panel->SetSizer(vsizer); auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:"))); - p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr, + p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr, "Hex files (*.hex)|*.hex|All files|*.*"); auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:"))); @@ -758,7 +768,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : // Experience says it needs to be 1, otherwise things won't get sized properly. vsizer->Add(p->spoiler, 1, wxEXPAND | wxBOTTOM, SPACING); - p->btn_close = new wxButton(panel, wxID_CLOSE); + p->btn_close = new wxButton(panel, wxID_CLOSE, _(L("Close"))); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac p->btn_flash = new wxButton(panel, wxID_ANY, p->btn_flash_label_ready); p->btn_flash->Disable(); auto *bsizer = new wxBoxSizer(wxHORIZONTAL); @@ -769,10 +779,10 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : auto *topsizer = new wxBoxSizer(wxVERTICAL); topsizer->Add(panel, 1, wxEXPAND | wxALL, DIALOG_MARGIN); - SetMinSize(wxSize(MIN_WIDTH, MIN_HEIGHT)); + SetMinSize(wxSize(min_width, min_height)); SetSizerAndFit(topsizer); const auto size = GetSize(); - SetSize(std::max(size.GetWidth(), static_cast(MIN_WIDTH)), std::max(size.GetHeight(), static_cast(MIN_HEIGHT))); + SetSize(std::max(size.GetWidth(), static_cast(min_width)), std::max(size.GetHeight(), static_cast(min_height))); Layout(); SetEscapeId(wxID_CLOSE); // To close the dialog using "Esc" button @@ -786,13 +796,13 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : } }); - p->spoiler->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [this](wxCollapsiblePaneEvent &evt) { + p->spoiler->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [=](wxCollapsiblePaneEvent &evt) { if (evt.GetCollapsed()) { - this->SetMinSize(wxSize(MIN_WIDTH, MIN_HEIGHT)); + this->SetMinSize(wxSize(min_width, min_height)); const auto new_height = this->GetSize().GetHeight() - this->p->txt_stdout->GetSize().GetHeight(); this->SetSize(this->GetSize().GetWidth(), new_height); } else { - this->SetMinSize(wxSize(MIN_WIDTH, MIN_HEIGHT_EXPANDED)); + this->SetMinSize(wxSize(min_width, min_height_expanded)); } this->Layout(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5f51596bb..5f7ef3c55 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -84,112 +84,6 @@ static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f namespace Slic3r { namespace GUI { -bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords) -{ - m_vertices.clear(); - m_tex_coords.clear(); - - unsigned int v_size = 9 * (unsigned int)triangles.size(); - unsigned int t_size = 6 * (unsigned int)triangles.size(); - if (v_size == 0) - return false; - - m_vertices = std::vector(v_size, 0.0f); - if (generate_tex_coords) - m_tex_coords = std::vector(t_size, 0.0f); - - float min_x = unscale(triangles[0].points[0](0)); - float min_y = unscale(triangles[0].points[0](1)); - float max_x = min_x; - float max_y = min_y; - - unsigned int v_coord = 0; - unsigned int t_coord = 0; - for (const Polygon& t : triangles) - { - for (unsigned int v = 0; v < 3; ++v) - { - const Point& p = t.points[v]; - float x = unscale(p(0)); - float y = unscale(p(1)); - - m_vertices[v_coord++] = x; - m_vertices[v_coord++] = y; - m_vertices[v_coord++] = z; - - if (generate_tex_coords) - { - m_tex_coords[t_coord++] = x; - m_tex_coords[t_coord++] = y; - - min_x = std::min(min_x, x); - max_x = std::max(max_x, x); - min_y = std::min(min_y, y); - max_y = std::max(max_y, y); - } - } - } - - if (generate_tex_coords) - { - float size_x = max_x - min_x; - float size_y = max_y - min_y; - - if ((size_x != 0.0f) && (size_y != 0.0f)) - { - float inv_size_x = 1.0f / size_x; - float inv_size_y = -1.0f / size_y; - for (unsigned int i = 0; i < m_tex_coords.size(); i += 2) - { - m_tex_coords[i] = (m_tex_coords[i] - min_x) * inv_size_x; - m_tex_coords[i + 1] = (m_tex_coords[i + 1] - min_y) * inv_size_y; - } - } - } - - return true; -} - -bool GeometryBuffer::set_from_lines(const Lines& lines, float z) -{ - m_vertices.clear(); - m_tex_coords.clear(); - - unsigned int size = 6 * (unsigned int)lines.size(); - if (size == 0) - return false; - - m_vertices = std::vector(size, 0.0f); - - unsigned int coord = 0; - for (const Line& l : lines) - { - m_vertices[coord++] = unscale(l.a(0)); - m_vertices[coord++] = unscale(l.a(1)); - m_vertices[coord++] = z; - m_vertices[coord++] = unscale(l.b(0)); - m_vertices[coord++] = unscale(l.b(1)); - m_vertices[coord++] = z; - } - - return true; -} - -const float* GeometryBuffer::get_vertices() const -{ - return m_vertices.data(); -} - -const float* GeometryBuffer::get_tex_coords() const -{ - return m_tex_coords.data(); -} - -unsigned int GeometryBuffer::get_vertices_count() const -{ - return (unsigned int)m_vertices.size() / 3; -} - Size::Size() : m_width(0) , m_height(0) @@ -344,584 +238,7 @@ void GLCanvas3D::Camera::set_scene_box(const BoundingBoxf3& box, GLCanvas3D& can } } -GLCanvas3D::Bed::Bed() - : m_type("Custom") - , m_scale_factor(1.0f) -{ -} - -bool GLCanvas3D::Bed::is_prusa() const -{ - return (m_type == "MK2") || (m_type == "MK3") || (m_type == "SL1"); -} - -bool GLCanvas3D::Bed::is_custom() const -{ - return !is_prusa(); -} - -const Pointfs& GLCanvas3D::Bed::get_shape() const -{ - return m_shape; -} - -bool GLCanvas3D::Bed::set_shape(const Pointfs& shape) -{ -#if ENABLE_REWORKED_BED_SHAPE_CHANGE - std::string new_type = _detect_type(shape); -#else - std::string new_type = _detect_type(); -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE - if (m_shape == shape && m_type == new_type) - // No change, no need to update the UI. - return false; - - m_shape = shape; - m_type = new_type; - - _calc_bounding_box(); - - ExPolygon poly; - for (const Vec2d& p : m_shape) - { - poly.contour.append(Point(scale_(p(0)), scale_(p(1)))); - } - - _calc_triangles(poly); - - const BoundingBox& bed_bbox = poly.contour.bounding_box(); - _calc_gridlines(poly, bed_bbox); - - m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour; - // Let the calee to update the UI. - return true; -} - -const BoundingBoxf3& GLCanvas3D::Bed::get_bounding_box() const -{ - return m_bounding_box; -} - -bool GLCanvas3D::Bed::contains(const Point& point) const -{ - return m_polygon.contains(point); -} - -Point GLCanvas3D::Bed::point_projection(const Point& point) const -{ - return m_polygon.point_projection(point); -} - -#if ENABLE_PRINT_BED_MODELS -void GLCanvas3D::Bed::render(float theta, bool useVBOs, float scale_factor) const -{ - m_scale_factor = scale_factor; - - if (m_type == "MK2") - { - _render_prusa("mk2", theta, useVBOs); - } - else if (m_type == "MK3") - { - _render_prusa("mk3", theta, useVBOs); - } - else if (m_type == "SL1") - { - _render_prusa("sl1", theta, useVBOs); - } - else - { - _render_custom(m_type, theta, useVBOs); - } -} -#else -void GLCanvas3D::Bed::render(float theta, float scale_factor) const -{ - m_scale_factor = scale_factor; - - if (m_type == "MK2") - { - _render_prusa("mk2", theta); - } - else if (m_type == "MK3") - { - _render_prusa("mk3", theta); - } - else if (m_type == "SL1") - { - _render_prusa("sl1", theta); - } - else if (m_type == "MK2") - { - _render_default(m_type, theta); - } -} -#endif // ENABLE_PRINT_BED_MODELS - -void GLCanvas3D::Bed::_calc_bounding_box() -{ - m_bounding_box = BoundingBoxf3(); - for (const Vec2d& p : m_shape) - { - m_bounding_box.merge(Vec3d(p(0), p(1), 0.0)); - } -} - -void GLCanvas3D::Bed::_calc_triangles(const ExPolygon& poly) -{ - Polygons triangles; - poly.triangulate(&triangles); - - if (!m_triangles.set_from_triangles(triangles, GROUND_Z, is_prusa())) - printf("Unable to create bed triangles\n"); -} - -void GLCanvas3D::Bed::_calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) -{ - Polylines axes_lines; - for (coord_t x = bed_bbox.min(0); x <= bed_bbox.max(0); x += scale_(10.0)) - { - Polyline line; - line.append(Point(x, bed_bbox.min(1))); - line.append(Point(x, bed_bbox.max(1))); - axes_lines.push_back(line); - } - for (coord_t y = bed_bbox.min(1); y <= bed_bbox.max(1); y += scale_(10.0)) - { - Polyline line; - line.append(Point(bed_bbox.min(0), y)); - line.append(Point(bed_bbox.max(0), y)); - axes_lines.push_back(line); - } - - // clip with a slightly grown expolygon because our lines lay on the contours and may get erroneously clipped - Lines gridlines = to_lines(intersection_pl(axes_lines, offset(poly, (float)SCALED_EPSILON))); - - // append bed contours - Lines contour_lines = to_lines(poly); - std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); - - if (!m_gridlines.set_from_lines(gridlines, GROUND_Z)) - printf("Unable to create bed grid lines\n"); -} - -#if ENABLE_REWORKED_BED_SHAPE_CHANGE -std::string GLCanvas3D::Bed::_detect_type(const Pointfs& shape) const -#else -std::string GLCanvas3D::Bed::_detect_type() const -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE -{ - std::string type = "Custom"; - - auto bundle = wxGetApp().preset_bundle; - if (bundle != nullptr) - { - const Preset* curr = &bundle->printers.get_selected_preset(); - while (curr != nullptr) - { - if (curr->config.has("bed_shape")) - { -#if ENABLE_REWORKED_BED_SHAPE_CHANGE - if ((curr->vendor != nullptr) && (curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) - { - if (boost::contains(curr->name, "SL1")) - { - type = "SL1"; - break; - } - else if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5")) - { - type = "MK3"; - break; - } - else if (boost::contains(curr->name, "MK2")) - { - type = "MK2"; - break; - } - } -#else - if (boost::contains(curr->name, "SL1")) - { - //FIXME add a condition on the size of the print bed? - type = "SL1"; - break; - } - else if (_are_equal(m_shape, dynamic_cast(curr->config.option("bed_shape"))->values)) - { - if ((curr->vendor != nullptr) && (curr->vendor->name == "Prusa Research")) - { - if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5")) - { - type = "MK3"; - break; - } else if (boost::contains(curr->name, "MK2")) - { - type = "MK2"; - break; - } - } - } -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE - } - - curr = bundle->printers.get_preset_parent(*curr); - } - } - - return type; -} - -#if ENABLE_PRINT_BED_MODELS -void GLCanvas3D::Bed::_render_prusa(const std::string &key, float theta, bool useVBOs) const -#else -void GLCanvas3D::Bed::_render_prusa(const std::string &key, float theta) const -#endif // ENABLE_PRINT_BED_MODELS -{ - std::string tex_path = resources_dir() + "/icons/bed/" + key; - - // use higher resolution images if graphic card allows - GLint max_tex_size; - ::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); - - // temporary set to lowest resolution - max_tex_size = 2048; - - if (max_tex_size >= 8192) - tex_path += "_8192"; - else if (max_tex_size >= 4096) - tex_path += "_4096"; - -#if ENABLE_PRINT_BED_MODELS - std::string model_path = resources_dir() + "/models/" + key; -#endif // ENABLE_PRINT_BED_MODELS - -#if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - // use anisotropic filter if graphic card allows - GLfloat max_anisotropy = 0.0f; - if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) - ::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); -#endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - - std::string filename = tex_path + "_top.png"; - if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) - { - if (!m_top_texture.load_from_file(filename, true)) - { - _render_default(); - return; - } -#if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - if (max_anisotropy > 0.0f) - { - ::glBindTexture(GL_TEXTURE_2D, m_top_texture.get_id()); - ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); - ::glBindTexture(GL_TEXTURE_2D, 0); - } -#endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - } - - filename = tex_path + "_bottom.png"; - if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename)) - { - if (!m_bottom_texture.load_from_file(filename, true)) - { - _render_default(); - return; - } -#if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - if (max_anisotropy > 0.0f) - { - ::glBindTexture(GL_TEXTURE_2D, m_bottom_texture.get_id()); - ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); - ::glBindTexture(GL_TEXTURE_2D, 0); - } -#endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - } - -#if ENABLE_PRINT_BED_MODELS - if (theta <= 90.0f) - { - filename = model_path + "_bed.stl"; - if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, useVBOs)) { - Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2)); - if (key == "mk2") - // hardcoded value to match the stl model - offset += Vec3d(0.0, 7.5, -0.03); - else if (key == "mk3") - // hardcoded value to match the stl model - offset += Vec3d(0.0, 5.5, 2.43); - else if (key == "sl1") - // hardcoded value to match the stl model - offset += Vec3d(0.0, 0.0, -0.03); - - m_model.center_around(offset); - } - - if (!m_model.get_filename().empty()) - { - ::glEnable(GL_LIGHTING); - m_model.render(); - ::glDisable(GL_LIGHTING); - } - } -#endif // ENABLE_PRINT_BED_MODELS - - unsigned int triangles_vcount = m_triangles.get_vertices_count(); - if (triangles_vcount > 0) - { - ::glEnable(GL_DEPTH_TEST); - ::glDepthMask(GL_FALSE); - - ::glEnable(GL_BLEND); - ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - ::glEnable(GL_TEXTURE_2D); - ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - ::glEnableClientState(GL_VERTEX_ARRAY); - ::glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - if (theta > 90.0f) - ::glFrontFace(GL_CW); - - ::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id()); - ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()); - ::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords()); - ::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount); - - if (theta > 90.0f) - ::glFrontFace(GL_CCW); - - ::glBindTexture(GL_TEXTURE_2D, 0); - ::glDisableClientState(GL_TEXTURE_COORD_ARRAY); - ::glDisableClientState(GL_VERTEX_ARRAY); - - ::glDisable(GL_TEXTURE_2D); - - ::glDisable(GL_BLEND); - ::glDepthMask(GL_TRUE); - } -} - -void GLCanvas3D::Bed::_render_default() const -{ - m_top_texture.reset(); - m_bottom_texture.reset(); - - unsigned int triangles_vcount = m_triangles.get_vertices_count(); - if (triangles_vcount > 0) { - ::glEnable(GL_LIGHTING); - ::glDisable(GL_DEPTH_TEST); - - ::glEnable(GL_BLEND); - ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - ::glEnableClientState(GL_VERTEX_ARRAY); - - ::glColor4f(0.35f, 0.35f, 0.35f, 0.4f); - ::glNormal3d(0.0f, 0.0f, 1.0f); - ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()); - ::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount); - - // draw grid - unsigned int gridlines_vcount = m_gridlines.get_vertices_count(); - - // we need depth test for grid, otherwise it would disappear when looking the object from below - ::glEnable(GL_DEPTH_TEST); - ::glLineWidth(3.0f * m_scale_factor); - ::glColor4f(0.2f, 0.2f, 0.2f, 0.4f); - ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices()); - ::glDrawArrays(GL_LINES, 0, (GLsizei)gridlines_vcount); - - ::glDisableClientState(GL_VERTEX_ARRAY); - - ::glDisable(GL_BLEND); - ::glDisable(GL_LIGHTING); - } - -} - -#if ENABLE_PRINT_BED_MODELS -void GLCanvas3D::Bed::_render_custom(const std::string &key, float theta, bool useVBOs) const -#else -void GLCanvas3D::Bed::_render_custom(const std::string &key, float theta) const -#endif // ENABLE_PRINT_BED_MODELS -{ - std::string tex_path = resources_dir() + "/icons/bed/" + key; -#if ENABLE_PRINT_BED_MODELS - std::string model_path = resources_dir() + "/models/" + key; -#endif // ENABLE_PRINT_BED_MODELS - -#if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - GLfloat max_anisotropy = 0.0f; - ::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); -#endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - - std::string filename = tex_path + "_top.png"; - if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) { - if (!m_top_texture.load_from_file(filename, true)) { - _render_default(); - return; - } -#if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - if (max_anisotropy > 0.0f) { - ::glBindTexture(GL_TEXTURE_2D, m_top_texture.get_id()); - ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); - ::glBindTexture(GL_TEXTURE_2D, 0); - } -#endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - } - - filename = tex_path + "_bottom.png"; - if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename)) { - if (!m_bottom_texture.load_from_file(filename, true)) { - _render_default(); - return; - } -#if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - if (max_anisotropy > 0.0f) { - ::glBindTexture(GL_TEXTURE_2D, m_bottom_texture.get_id()); - ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); - ::glBindTexture(GL_TEXTURE_2D, 0); - } -#endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES - } - -#if ENABLE_PRINT_BED_MODELS - if (theta <= 90.0f) { - filename = model_path + "_bed.stl"; - if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, useVBOs)) { - Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.1 + 0.5 * m_model.get_bounding_box().size()(2)); - m_model.center_around(offset); - } - - if (!m_model.get_filename().empty()) { - ::glEnable(GL_LIGHTING); - m_model.render(); - ::glDisable(GL_LIGHTING); - } - } -#endif // ENABLE_PRINT_BED_MODELS - - unsigned int triangles_vcount = m_triangles.get_vertices_count(); - if (triangles_vcount > 0) { - ::glEnable(GL_DEPTH_TEST); - ::glDepthMask(GL_FALSE); - - ::glEnable(GL_BLEND); - ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - ::glEnable(GL_TEXTURE_2D); - ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - ::glEnableClientState(GL_VERTEX_ARRAY); - ::glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - if (theta > 90.0f) - ::glFrontFace(GL_CW); - - ::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id()); - ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()); - ::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords()); - ::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount); - - if (theta > 90.0f) - ::glFrontFace(GL_CCW); - - ::glBindTexture(GL_TEXTURE_2D, 0); - ::glDisableClientState(GL_TEXTURE_COORD_ARRAY); - ::glDisableClientState(GL_VERTEX_ARRAY); - - ::glDisable(GL_TEXTURE_2D); - - ::glDisable(GL_BLEND); - ::glDepthMask(GL_TRUE); - } -} - -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE -bool GLCanvas3D::Bed::_are_equal(const Pointfs& bed_1, const Pointfs& bed_2) -{ - if (bed_1.size() != bed_2.size()) - return false; - - for (unsigned int i = 0; i < (unsigned int)bed_1.size(); ++i) - { - if (bed_1[i] != bed_2[i]) - return false; - } - - return true; -} -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - -const double GLCanvas3D::Axes::Radius = 0.5; -const double GLCanvas3D::Axes::ArrowBaseRadius = 2.5 * GLCanvas3D::Axes::Radius; -const double GLCanvas3D::Axes::ArrowLength = 5.0; - -GLCanvas3D::Axes::Axes() - : origin(Vec3d::Zero()) - , length(Vec3d::Zero()) -{ - m_quadric = ::gluNewQuadric(); - if (m_quadric != nullptr) - ::gluQuadricDrawStyle(m_quadric, GLU_FILL); -} - -GLCanvas3D::Axes::~Axes() -{ - if (m_quadric != nullptr) - ::gluDeleteQuadric(m_quadric); -} - -void GLCanvas3D::Axes::render() const -{ - if (m_quadric == nullptr) - return; - - ::glEnable(GL_DEPTH_TEST); - ::glEnable(GL_LIGHTING); - - // x axis - ::glColor3f(1.0f, 0.0f, 0.0f); - ::glPushMatrix(); - ::glTranslated(origin(0), origin(1), origin(2)); - ::glRotated(90.0, 0.0, 1.0, 0.0); - render_axis(length(0)); - ::glPopMatrix(); - - // y axis - ::glColor3f(0.0f, 1.0f, 0.0f); - ::glPushMatrix(); - ::glTranslated(origin(0), origin(1), origin(2)); - ::glRotated(-90.0, 1.0, 0.0, 0.0); - render_axis(length(1)); - ::glPopMatrix(); - - // z axis - ::glColor3f(0.0f, 0.0f, 1.0f); - ::glPushMatrix(); - ::glTranslated(origin(0), origin(1), origin(2)); - render_axis(length(2)); - ::glPopMatrix(); - - ::glDisable(GL_LIGHTING); -} - -void GLCanvas3D::Axes::render_axis(double length) const -{ - ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); - ::gluCylinder(m_quadric, Radius, Radius, length, 32, 1); - ::gluQuadricOrientation(m_quadric, GLU_INSIDE); - ::gluDisk(m_quadric, 0.0, Radius, 32, 1); - ::glTranslated(0.0, 0.0, length); - ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); - ::gluCylinder(m_quadric, ArrowBaseRadius, 0.0, ArrowLength, 32, 1); - ::gluQuadricOrientation(m_quadric, GLU_INSIDE); - ::gluDisk(m_quadric, 0.0, ArrowBaseRadius, 32, 1); -} - +#if !ENABLE_TEXTURES_FROM_SVG GLCanvas3D::Shader::Shader() : m_shader(nullptr) { @@ -1000,6 +317,7 @@ void GLCanvas3D::Shader::_reset() m_shader = nullptr; } } +#endif // !ENABLE_TEXTURES_FROM_SVG GLCanvas3D::LayersEditing::LayersEditing() : m_use_legacy_opengl(false) @@ -1578,8 +896,7 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio if (needs_reset) clear(); - if (volume->is_modifier) - m_mode = Volume; + m_mode = volume->is_modifier ? Volume : Instance; switch (m_mode) { @@ -1943,17 +1260,22 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to return (axis.z() < 0) ? -angle : angle; } -void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) +// Rotate an object around one of the axes. Only one rotation component is expected to be changing. +void GLCanvas3D::Selection::rotate(const Vec3d& rotation, GLCanvas3D::TransformationType transformation_type) { if (!m_valid) return; + // Only relative rotation values are allowed in the world coordinate system. + assert(! transformation_type.world() || transformation_type.relative()); + int rot_axis_max; + //FIXME this does not work for absolute rotations (transformation_type.absolute() is true) rotation.cwiseAbs().maxCoeff(&rot_axis_max); // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it. std::vector object_instance_first(m_model->objects.size(), -1); - auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) { + auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) { int first_volume_idx = object_instance_first[volume.object_idx()]; if (rot_axis_max != 2 && first_volume_idx != -1) { // Generic rotation, but no rotation around the Z axis. @@ -1965,11 +1287,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); } else { // extracts rotations from the composed transformation - Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); - Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); - if (rot_axis_max == 2 && !local) + Vec3d new_rotation = transformation_type.world() ? + Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : + transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); + if (rot_axis_max == 2 && transformation_type.joint()) { // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis. - volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + double z_diff = rotation_diff_z(new_rotation, m_cache.volumes_data[i].get_instance_rotation()); + volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + } volume.set_instance_rotation(new_rotation); object_instance_first[volume.object_idx()] = i; } @@ -1982,7 +1307,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) rotate_instance(volume, i); else if (is_single_volume() || is_single_modifier()) { - if (local) + if (transformation_type.independent()) volume.set_volume_rotation(volume.get_volume_rotation() + rotation); else { @@ -2000,7 +1325,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) // extracts rotations from the composed transformation Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); - if (!local) + if (transformation_type.joint()) { Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); @@ -3240,6 +2565,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec float cnv_h = (float)canvas.get_canvas_size().get_height(); float height = _get_total_overlay_height(); float top_y = 0.5f * (cnv_h - height) + m_overlay_border; + for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { if ((it->second == nullptr) || !it->second->is_selectable()) @@ -3522,42 +2848,28 @@ void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object) reinterpret_cast(it->second)->set_flattening_data(model_object); } -#if ENABLE_SLA_SUPPORT_GIZMO_MOD void GLCanvas3D::Gizmos::set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection) -#else -void GLCanvas3D::Gizmos::set_model_object_ptr(ModelObject* model_object) -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD { if (!m_enabled) return; GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); if (it != m_gizmos.end()) -#if ENABLE_SLA_SUPPORT_GIZMO_MOD reinterpret_cast(it->second)->set_sla_support_data(model_object, selection); -#else - reinterpret_cast(it->second)->set_model_object_ptr(model_object); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD } -void GLCanvas3D::Gizmos::clicked_on_object(const Vec2d& mouse_position) + +// Returns true if the gizmo used the event to do something, false otherwise. +bool GLCanvas3D::Gizmos::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down) { if (!m_enabled) - return; + return false; GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); if (it != m_gizmos.end()) - reinterpret_cast(it->second)->clicked_on_object(mouse_position); -} + return reinterpret_cast(it->second)->mouse_event(action, mouse_position, shift_down); -void GLCanvas3D::Gizmos::delete_current_grabber(bool delete_all) -{ - if (!m_enabled) - return; - - GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); - if (it != m_gizmos.end()) - reinterpret_cast(it->second)->delete_current_grabber(delete_all); + return false; } void GLCanvas3D::Gizmos::render_current_gizmo(const GLCanvas3D::Selection& selection) const @@ -3772,7 +3084,40 @@ GLCanvas3D::WarningTexture::WarningTexture() { } -bool GLCanvas3D::WarningTexture::generate(const std::string& msg, const GLCanvas3D& canvas) +void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas) +{ + auto it = std::find(m_warnings.begin(), m_warnings.end(), warning); + + if (state) { + if (it != m_warnings.end()) // this warning is already set to be shown + return; + + m_warnings.push_back(warning); + std::sort(m_warnings.begin(), m_warnings.end()); + } + else { + if (it == m_warnings.end()) // deactivating something that is not active is an easy task + return; + + m_warnings.erase(it); + if (m_warnings.empty()) { // nothing remains to be shown + reset(); + return; + } + } + + // Look at the end of our vector and generate proper texture. + std::string text; + switch (m_warnings.back()) { + case ObjectOutside : text = L("Detected object outside print volume"); break; + case ToolpathOutside : text = L("Detected toolpath outside print volume"); break; + case SomethingNotShown : text = L("Some objects are not visible when editing supports"); break; + } + + _generate(text, canvas); // GUI::GLTexture::reset() is called at the beginning of generate(...) +} + +bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas) { reset(); @@ -3845,6 +3190,9 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg, const GLCanvas void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const { + if (m_warnings.empty()) + return; + if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { ::glDisable(GL_DEPTH_TEST); @@ -3938,7 +3286,8 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c wxMemoryDC mask_memDC; // calculate scaling - const float scale = canvas.get_canvas_size().get_scale_factor(); + const float scale_gl = canvas.get_canvas_size().get_scale_factor(); + const float scale = scale_gl * wxGetApp().em_unit()*0.1; // get scale from em_unit() value, because of get_scale_factor() return 1 const int scaled_square = std::floor((float)Px_Square * scale); const int scaled_title_offset = Px_Title_Offset * scale; const int scaled_text_offset = Px_Text_Offset * scale; @@ -3946,7 +3295,7 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c const int scaled_border = Px_Border * scale; // select default font - const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale); + const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl); memDC.SetFont(font); mask_memDC.SetFont(font); @@ -4143,6 +3492,8 @@ wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); wxDEFINE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent); GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) : m_canvas(canvas) @@ -4151,6 +3502,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_retina_helper(nullptr) #endif , m_in_render(false) + , m_bed(nullptr) , m_toolbar(GLToolbar::Normal) , m_view_toolbar(nullptr) , m_use_clipping_planes(false) @@ -4161,15 +3513,10 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_dirty(true) , m_initialized(false) , m_use_VBOs(false) -#if ENABLE_REWORKED_BED_SHAPE_CHANGE , m_requires_zoom_to_bed(false) -#else - , m_force_zoom_to_bed_enabled(false) -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE , m_apply_zoom_to_volumes_filter(false) , m_hover_volume_id(-1) , m_toolbar_action_running(false) - , m_warning_texture_enabled(false) , m_legend_texture_enabled(false) , m_picking_enabled(false) , m_moving_enabled(false) @@ -4177,8 +3524,10 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_multisample_allowed(false) , m_regenerate_volumes(true) , m_moving(false) + , m_tab_down(false) , m_color_by("volume") , m_reload_delayed(false) + , m_render_sla_auxiliaries(true) #if !ENABLE_IMGUI , m_external_gizmo_widgets_parent(nullptr) #endif // not ENABLE_IMGUI @@ -4326,8 +3675,7 @@ void GLCanvas3D::reset_volumes() m_dirty = true; } - enable_warning_texture(false); - _reset_warning_texture(); + _set_warning_texture(WarningTexture::ObjectOutside, false); } int GLCanvas3D::check_volumes_outside_state() const @@ -4337,6 +3685,34 @@ int GLCanvas3D::check_volumes_outside_state() const return (int)state; } +void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible) +{ + for (GLVolume* vol : m_volumes.volumes) { + if (vol->composite_id.volume_id < 0) + vol->is_active = visible; + } + + m_render_sla_auxiliaries = visible; +} + +void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject* mo, int instance_idx) +{ + for (GLVolume* vol : m_volumes.volumes) { + if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx)) + vol->is_active = visible; + } + if (visible && !mo) + toggle_sla_auxiliaries_visibility(true); + + if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1)) + _set_warning_texture(WarningTexture::SomethingNotShown, true); + + if (!mo && visible) + _set_warning_texture(WarningTexture::SomethingNotShown, false); +} + + void GLCanvas3D::set_config(const DynamicPrintConfig* config) { m_config = config; @@ -4354,37 +3730,13 @@ void GLCanvas3D::set_model(Model* model) m_selection.set_model(m_model); } -void GLCanvas3D::set_bed_shape(const Pointfs& shape) +void GLCanvas3D::bed_shape_changed() { - bool new_shape = m_bed.set_shape(shape); - -#if ENABLE_REWORKED_BED_SHAPE_CHANGE - if (new_shape) - { - // Set the origin and size for painting of the coordinate system axes. - m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); - set_bed_axes_length(0.1 * m_bed.get_bounding_box().max_size()); m_camera.set_scene_box(scene_bounding_box(), *this); m_requires_zoom_to_bed = true; m_dirty = true; } -#else - // Set the origin and size for painting of the coordinate system axes. - m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); - set_bed_axes_length(0.1 * m_bed.get_bounding_box().max_size()); - - if (new_shape) - zoom_to_bed(); - - m_dirty = true; -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE -} - -void GLCanvas3D::set_bed_axes_length(double length) -{ - m_axes.length = length * Vec3d::Ones(); -} void GLCanvas3D::set_color_by(const std::string& value) { @@ -4410,7 +3762,9 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const BoundingBoxf3 GLCanvas3D::scene_bounding_box() const { BoundingBoxf3 bb = volumes_bounding_box(); - bb.merge(m_bed.get_bounding_box()); + if (m_bed != nullptr) + bb.merge(m_bed->get_bounding_box()); + if (m_config != nullptr) { double h = m_config->opt_float("max_print_height"); @@ -4447,11 +3801,6 @@ void GLCanvas3D::enable_layers_editing(bool enable) } } -void GLCanvas3D::enable_warning_texture(bool enable) -{ - m_warning_texture_enabled = enable; -} - void GLCanvas3D::enable_legend_texture(bool enable) { m_legend_texture_enabled = enable; @@ -4478,13 +3827,6 @@ void GLCanvas3D::enable_toolbar(bool enable) m_toolbar.set_enabled(enable); } -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE -void GLCanvas3D::enable_force_zoom_to_bed(bool enable) -{ - m_force_zoom_to_bed_enabled = enable; -} -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - void GLCanvas3D::enable_dynamic_background(bool enable) { m_dynamic_background_enabled = enable; @@ -4510,7 +3852,8 @@ bool GLCanvas3D::is_toolbar_item_pressed(const std::string& name) const void GLCanvas3D::zoom_to_bed() { - _zoom_to_bounding_box(m_bed.get_bounding_box()); + if (m_bed != nullptr) + _zoom_to_bounding_box(m_bed->get_bounding_box()); } void GLCanvas3D::zoom_to_volumes() @@ -4623,12 +3966,10 @@ void GLCanvas3D::render() if (!_set_current() || !_3DScene::init(m_canvas)) return; -#if ENABLE_REWORKED_BED_SHAPE_CHANGE - if (m_bed.get_shape().empty()) + if ((m_bed != nullptr) && m_bed->get_shape().empty()) { // this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE - if (m_config != nullptr) - set_bed_shape(m_config->opt("bed_shape")->values); + post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE)); } if (m_requires_zoom_to_bed) @@ -4638,10 +3979,6 @@ void GLCanvas3D::render() _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); m_requires_zoom_to_bed = false; } -#else - if (m_force_zoom_to_bed_enabled) - _force_zoom_to_bed(); -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE _camera_tranform(); @@ -4655,7 +3992,7 @@ void GLCanvas3D::render() // absolute value of the rotation theta = 360.f - theta; - bool is_custom_bed = m_bed.is_custom(); + bool is_custom_bed = (m_bed == nullptr) || m_bed->is_custom(); #if ENABLE_IMGUI wxGetApp().imgui()->new_frame(); @@ -4691,9 +4028,9 @@ void GLCanvas3D::render() // this position is used later into on_mouse() to drag the objects m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast()); + _render_current_gizmo(); _render_selection_sidebar_hints(); - _render_current_gizmo(); #if ENABLE_SHOW_CAMERA_TARGET _render_camera_target(); #endif // ENABLE_SHOW_CAMERA_TARGET @@ -4937,10 +4274,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (m_reload_delayed) return; -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - set_bed_shape(dynamic_cast(m_config->option("bed_shape"))->values); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - if (m_regenerate_volumes) { m_volumes.volumes = std::move(glvolumes_new); @@ -5070,22 +4403,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (!contained) { - enable_warning_texture(true); - _generate_warning_texture(L("Detected object outside print volume")); + _set_warning_texture(WarningTexture::ObjectOutside, true); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside)); } else { - enable_warning_texture(false); m_volumes.reset_outside_state(); - _reset_warning_texture(); + _set_warning_texture(WarningTexture::ObjectOutside, false); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty())); } } else { - enable_warning_texture(false); - _reset_warning_texture(); + _set_warning_texture(WarningTexture::ObjectOutside, false); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } @@ -5201,6 +4531,8 @@ void GLCanvas3D::bind_event_handlers() m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this); m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this); m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this); + m_canvas->Bind(wxEVT_KEY_DOWN, &GLCanvas3D::on_key, this); + m_canvas->Bind(wxEVT_KEY_UP, &GLCanvas3D::on_key, this); m_canvas->Bind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); @@ -5226,6 +4558,8 @@ void GLCanvas3D::unbind_event_handlers() m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this); m_canvas->Unbind(wxEVT_IDLE, &GLCanvas3D::on_idle, this); m_canvas->Unbind(wxEVT_CHAR, &GLCanvas3D::on_char, this); + m_canvas->Unbind(wxEVT_KEY_DOWN, &GLCanvas3D::on_key, this); + m_canvas->Unbind(wxEVT_KEY_UP, &GLCanvas3D::on_key, this); m_canvas->Unbind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Unbind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Unbind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); @@ -5262,6 +4596,15 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) // see include/wx/defs.h enum wxKeyCode int keyCode = evt.GetKeyCode(); int ctrlMask = wxMOD_CONTROL; + +#if ENABLE_IMGUI + auto imgui = wxGetApp().imgui(); + if (imgui->update_key_data(evt)) { + render(); + return; + } +#endif // ENABLE_IMGUI + //#ifdef __APPLE__ // ctrlMask |= wxMOD_RAW_CONTROL; //#endif /* __APPLE__ */ @@ -5269,7 +4612,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) switch (keyCode) { case 'a': case 'A': - case WXK_CONTROL_A: post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); break; + case WXK_CONTROL_A: + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::SelectAll)) // Sla gizmo selects all support points + m_dirty = true; + else + post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); + break; #ifdef __APPLE__ case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead. #else /* __APPLE__ */ @@ -5284,13 +4632,30 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) switch (keyCode) { // key ESC - case WXK_ESCAPE: { m_gizmos.reset_all_states(); m_dirty = true; break; } + case WXK_ESCAPE: { + if (m_gizmos.get_current_type() != Gizmos::SlaSupports || !m_gizmos.mouse_event(SLAGizmoEventType::DiscardChanges)) + m_gizmos.reset_all_states(); + m_dirty = true; + break; + } + + case WXK_RETURN: { + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::ApplyChanges)) + m_dirty = true; + break; + } + #ifdef __APPLE__ case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead. #else /* __APPLE__ */ case WXK_DELETE: #endif /* __APPLE__ */ - post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE)); break; + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::Delete)) + m_dirty = true; + else + post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE)); + break; + case '0': { select_view("iso"); break; } case '1': { select_view("top"); break; } case '2': { select_view("bottom"); break; } @@ -5302,7 +4667,15 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '-': { post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); break; } case '?': { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; } case 'A': - case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } + case 'a': { + if (m_gizmos.get_current_type() == Gizmos::SlaSupports) { + if (m_gizmos.mouse_event(SLAGizmoEventType::AutomaticGeneration)) + m_dirty = true; + } + else + post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); + break; + } case 'B': case 'b': { zoom_to_bed(); break; } case 'I': @@ -5311,6 +4684,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'o': { set_camera_zoom(-1.0f); break; } case 'Z': case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; } + case 'M': + case 'm': { + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::ManualEditing)) { + m_dirty = true; + break; + } + } // intentional fallthrough default: { if (m_gizmos.handle_shortcut(keyCode, m_selection)) @@ -5327,6 +4707,38 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) } } +void GLCanvas3D::on_key(wxKeyEvent& evt) +{ + const int keyCode = evt.GetKeyCode(); + +#if ENABLE_IMGUI + auto imgui = wxGetApp().imgui(); + if (imgui->update_key_data(evt)) { + render(); + } else +#endif // ENABLE_IMGUI + if (evt.GetEventType() == wxEVT_KEY_UP) { + if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) { + // Enable switching between 3D and Preview with Tab + // m_canvas->HandleAsNavigationKey(evt); // XXX: Doesn't work in some cases / on Linux + post_event(SimpleEvent(EVT_GLCANVAS_TAB)); + } else if (m_gizmos.get_current_type() == Gizmos::SlaSupports && keyCode == WXK_SHIFT && m_gizmos.mouse_event(SLAGizmoEventType::ShiftUp)) { + // shift has been just released - SLA gizmo might want to close rectangular selection. + m_dirty = true; + } + } else if (evt.GetEventType() == wxEVT_KEY_DOWN) { + m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers(); + } + + if (keyCode != WXK_TAB + && keyCode != WXK_LEFT + && keyCode != WXK_UP + && keyCode != WXK_RIGHT + && keyCode != WXK_DOWN) { + evt.Skip(); // Needed to have EVT_CHAR generated as well + } +} + void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) { // Ignore the wheel events if the middle button is pressed. @@ -5369,6 +4781,54 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) _perform_layer_editing_action(); } +#ifndef NDEBUG +// #define SLIC3R_DEBUG_MOUSE_EVENTS +#endif + +#ifdef SLIC3R_DEBUG_MOUSE_EVENTS +std::string format_mouse_event_debug_message(const wxMouseEvent &evt) +{ + static int idx = 0; + char buf[2048]; + std::string out; + sprintf(buf, "Mouse Event %d - ", idx ++); + out = buf; + + if (evt.Entering()) + out += "Entering "; + if (evt.Leaving()) + out += "Leaving "; + if (evt.Dragging()) + out += "Dragging "; + if (evt.Moving()) + out += "Moving "; + if (evt.Magnify()) + out += "Magnify "; + if (evt.LeftDown()) + out += "LeftDown "; + if (evt.LeftUp()) + out += "LeftUp "; + if (evt.LeftDClick()) + out += "LeftDClick "; + if (evt.MiddleDown()) + out += "MiddleDown "; + if (evt.MiddleUp()) + out += "MiddleUp "; + if (evt.MiddleDClick()) + out += "MiddleDClick "; + if (evt.RightDown()) + out += "RightDown "; + if (evt.RightUp()) + out += "RightUp "; + if (evt.RightDClick()) + out += "RightDClick "; + + sprintf(buf, "(%d, %d)", evt.GetX(), evt.GetY()); + out += buf; + return out; +} +#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */ + void GLCanvas3D::on_mouse(wxMouseEvent& evt) { #if ENABLE_RETINA_GL @@ -5377,17 +4837,37 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) evt.SetY(evt.GetY() * scale); #endif + Point pos(evt.GetX(), evt.GetY()); + #if ENABLE_IMGUI - auto imgui = wxGetApp().imgui(); + ImGuiWrapper *imgui = wxGetApp().imgui(); if (imgui->update_mouse_data(evt)) { + m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast(); render(); - if (imgui->want_any_input()) { +#ifdef SLIC3R_DEBUG_MOUSE_EVENTS + printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str()); +#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */ return; } - } #endif // ENABLE_IMGUI - Point pos(evt.GetX(), evt.GetY()); +#ifdef __WXMSW__ + bool on_enter_workaround = false; + if (! evt.Entering() && ! evt.Leaving() && m_mouse.position.x() == -1.0) { + // Workaround for SPE-832: There seems to be a mouse event sent to the window before evt.Entering() + m_mouse.position = pos.cast(); + render(); +#ifdef SLIC3R_DEBUG_MOUSE_EVENTS + printf((format_mouse_event_debug_message(evt) + " - OnEnter workaround\n").c_str()); +#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */ + on_enter_workaround = true; + } else +#endif /* __WXMSW__ */ + { +#ifdef SLIC3R_DEBUG_MOUSE_EVENTS + printf((format_mouse_event_debug_message(evt) + " - other\n").c_str()); +#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */ + } if (m_picking_enabled) _set_current(); @@ -5407,6 +4887,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } #endif // ENABLE_MOVE_MIN_THRESHOLD + if (evt.ButtonDown() && wxWindow::FindFocus() != this->m_canvas) + // Grab keyboard focus on any mouse click event. + m_canvas->SetFocus(); + if (evt.Entering()) { //#if defined(__WXMSW__) || defined(__linux__) @@ -5420,8 +4904,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) auto *top_level_wnd = dynamic_cast(p); if (top_level_wnd && top_level_wnd->IsActive()) m_canvas->SetFocus(); + // forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while + // the context menu is shown, ensuring it to disappear if the mouse is outside any volume and to + // change the volume hover state if any is under the mouse + m_mouse.position = pos.cast(); + render(); } - m_mouse.set_start_position_2D_as_invalid(); //#endif } @@ -5429,6 +4917,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { // to remove hover on objects when the mouse goes out of this canvas m_mouse.position = Vec2d(-1.0, -1.0); + // ensure m_mouse.left_down is reset (it may happen when switching canvas) + m_mouse.left_down = false; m_dirty = true; } else if (evt.LeftDClick() && (toolbar_contains_mouse != -1)) @@ -5467,22 +4957,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } -#if !ENABLE_IMGUI - else if ((m_gizmos.get_current_type() == Gizmos::SlaSupports) && gizmo_reset_rect_contains(*this, pos(0), pos(1))) - { - if (evt.LeftDown()) - { - m_gizmos.delete_current_grabber(true); - m_dirty = true; - } - } -#endif // not ENABLE_IMGUI else if (!m_selection.is_empty() && gizmos_overlay_contains_mouse) { m_gizmos.update_on_off_state(*this, m_mouse.position, m_selection); _update_gizmos_data(); m_dirty = true; } + else if (evt.LeftDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown() && m_gizmos.mouse_event(SLAGizmoEventType::LeftDown, Vec2d(pos(0), pos(1)), evt.ShiftDown())) + { + // the gizmo got the event and took some action, there is no need to do anything more + } else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse()) { _update_gizmos_data(); @@ -5498,16 +4982,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } - else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse() && evt.RightDown()) { - if (m_gizmos.get_current_type() == Gizmos::SlaSupports) - m_gizmos.delete_current_grabber(); + else if ((selected_object_idx != -1) && evt.RightDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::RightDown)) + { + // event was taken care of by the SlaSupports gizmo } - else if (view_toolbar_contains_mouse != -1) + else if (evt.LeftDown() && (view_toolbar_contains_mouse != -1)) { if (m_view_toolbar != nullptr) m_view_toolbar->do_action((unsigned int)view_toolbar_contains_mouse, *this); } - else if (toolbar_contains_mouse != -1) + else if (evt.LeftDown() && (toolbar_contains_mouse != -1)) { m_toolbar_action_running = true; m_mouse.set_start_position_3D_as_invalid(); @@ -5556,7 +5040,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } // propagate event through callback - if (m_hover_volume_id != -1) { if (evt.LeftDown() && m_moving_enabled && (m_mouse.drag.move_volume_idx == -1)) @@ -5575,9 +5058,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.RightDown()) { + m_mouse.position = pos.cast(); // forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while - // the context menu is already shown, ensuring it to disappear if the mouse is outside any volume - m_mouse.position = Vec2d((double)pos(0), (double)pos(1)); + // the context menu is already shown render(); if (m_hover_volume_id != -1) { @@ -5591,14 +5074,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); _update_gizmos_data(); wxGetApp().obj_manipul()->update_settings_value(m_selection); - // forces a frame render to update the view before the context menu is shown - render(); +// // forces a frame render to update the view before the context menu is shown +// render(); Vec2d logical_pos = pos.cast(); #if ENABLE_RETINA_GL const float factor = m_retina_helper->get_scale_factor(); logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor)); -#endif +#endif // ENABLE_RETINA_GL post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos)); } } @@ -5606,7 +5089,8 @@ 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.move_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_gizmos.get_current_type() != Gizmos::SlaSupports /* don't allow dragging objects with the Sla gizmo on */) { #if ENABLE_MOVE_MIN_THRESHOLD if (!m_mouse.drag.move_requires_threshold) @@ -5614,11 +5098,42 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) #endif // ENABLE_MOVE_MIN_THRESHOLD m_mouse.dragging = true; + Vec3d cur_pos = m_mouse.drag.start_position_3D; + // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag + if (m_selection.contains_volume(m_hover_volume_id)) + { + if (m_camera.get_theta() == 90.0f) + { + // side view -> move selected volumes orthogonally to camera view direction + Linef3 ray = mouse_ray(pos); + Vec3d dir = ray.unit_vector(); + // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position + // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form + // in our case plane normal and ray direction are the same (orthogonal view) + // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal + Vec3d inters = ray.a + (m_mouse.drag.start_position_3D - ray.a).dot(dir) / dir.squaredNorm() * dir; + // vector from the starting position to the found intersection + Vec3d inters_vec = inters - m_mouse.drag.start_position_3D; + + // get the view matrix back from opengl + GLfloat matrix[16]; + ::glGetFloatv(GL_MODELVIEW_MATRIX, matrix); + Vec3d camera_right((double)matrix[0], (double)matrix[4], (double)matrix[8]); + + // finds projection of the vector along the camera right axis + double projection = inters_vec.dot(camera_right); + + cur_pos = m_mouse.drag.start_position_3D + projection * camera_right; + } + else + { + // Generic view // Get new position at the same Z of the initial click point. float z0 = 0.0f; float z1 = 1.0f; - // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag - Vec3d cur_pos = m_selection.contains_volume(m_hover_volume_id) ? Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D(2)) : m_mouse.drag.start_position_3D; + cur_pos = Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D(2)); + } + } m_regenerate_volumes = false; m_selection.translate(cur_pos - m_mouse.drag.start_position_3D); @@ -5656,7 +5171,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { // Apply new temporary rotations - m_selection.rotate(m_gizmos.get_rotation(), evt.AltDown()); + TransformationType transformation_type(TransformationType::World_Relative_Joint); + if (evt.AltDown()) + transformation_type.set_independent(); + m_selection.rotate(m_gizmos.get_rotation(), transformation_type); wxGetApp().obj_manipul()->update_settings_value(m_selection); break; } @@ -5666,7 +5184,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } - else if (evt.Dragging() && !gizmos_overlay_contains_mouse) + else if (evt.Dragging() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown() && m_gizmos.mouse_event(SLAGizmoEventType::Dragging, Vec2d(pos(0), pos(1)), evt.ShiftDown())) + { + // the gizmo got the event and took some action, no need to do anything more here + m_dirty = true; + } + // do not process dragging if the mouse is into any of the HUD elements + else if (evt.Dragging() && !gizmos_overlay_contains_mouse && (toolbar_contains_mouse == -1) && (view_toolbar_contains_mouse == -1)) { m_mouse.dragging = true; @@ -5675,7 +5199,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_layers_editing.state == LayersEditing::Editing) _perform_layer_editing_action(&evt); } - else if (evt.LeftIsDown()) + // do not process the dragging if the left mouse was set down in another canvas + else if (m_mouse.left_down && evt.LeftIsDown()) { // if dragging over blank area with left button, rotate #if ENABLE_MOVE_MIN_THRESHOLD @@ -5721,6 +5246,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) _stop_timer(); m_layers_editing.accept_changes(*this); } + else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports && !m_gizmos.is_dragging() + && !m_mouse.dragging && m_gizmos.mouse_event(SLAGizmoEventType::LeftUp, Vec2d(pos(0), pos(1)), evt.ShiftDown())) + { + // the gizmo got the event and took some action, no need to do anything more + } else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging) { m_regenerate_volumes = false; @@ -5730,16 +5260,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // of the scene with the background processing data should be performed. post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); } - else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_hover_volume_id != -1) + else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() + && !is_layers_editing_enabled() && (m_gizmos.get_current_type() != Gizmos::SlaSupports || !m_gizmos.mouse_event(SLAGizmoEventType::LeftUp, Vec2d(pos(0), pos(1)), evt.ShiftDown()))) { - int id = m_selection.get_object_idx(); + // SLA gizmo cannot be deselected by clicking in canvas area to avoid inadvertent unselection and losing manual changes + // that's why the mouse_event function was called so that the gizmo can refuse the deselection in manual editing mode - if ((id != -1) && (m_model != nullptr)) { - m_gizmos.clicked_on_object(Vec2d(pos(0), pos(1))); - } - } - else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled()) - { // deselect and propagate event through callback if (!evt.ShiftDown() && m_picking_enabled && !m_toolbar_action_running && !m_mouse.ignore_up_event) { @@ -5772,10 +5298,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) do_rotate(); break; } - case Gizmos::SlaSupports: - // End of mouse dragging, update the SLAPrint/SLAPrintObjects with the new support points. - post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - break; default: break; } @@ -5832,6 +5354,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else evt.Skip(); + +#ifdef __WXMSW__ + if (on_enter_workaround) + m_mouse.position = Vec2d(-1., -1.); +#endif /* __WXMSW__ */ } void GLCanvas3D::on_paint(wxPaintEvent& evt) @@ -6175,14 +5702,6 @@ bool GLCanvas3D::_is_shown_on_screen() const return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; } -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE -void GLCanvas3D::_force_zoom_to_bed() -{ - zoom_to_bed(); - m_force_zoom_to_bed_enabled = false; -} -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - bool GLCanvas3D::_init_toolbar() { if (!m_toolbar.is_enabled()) @@ -6225,7 +5744,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "add"; item.tooltip = GUI::L_str("Add...") + " [" + GUI::shortkey_ctrl_prefix() + "I]"; item.sprite_id = 0; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_ADD; if (!m_toolbar.add_item(item)) return false; @@ -6233,7 +5751,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "delete"; item.tooltip = GUI::L_str("Delete") + " [Del]"; item.sprite_id = 1; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_DELETE; if (!m_toolbar.add_item(item)) return false; @@ -6241,7 +5758,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "deleteall"; item.tooltip = GUI::L_str("Delete all") + " [" + GUI::shortkey_ctrl_prefix() + "Del]"; item.sprite_id = 2; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_DELETE_ALL; if (!m_toolbar.add_item(item)) return false; @@ -6249,7 +5765,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "arrange"; item.tooltip = GUI::L_str("Arrange [A]"); item.sprite_id = 3; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_ARRANGE; if (!m_toolbar.add_item(item)) return false; @@ -6260,7 +5775,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "more"; item.tooltip = GUI::L_str("Add instance [+]"); item.sprite_id = 4; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_MORE; if (!m_toolbar.add_item(item)) return false; @@ -6268,7 +5782,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "fewer"; item.tooltip = GUI::L_str("Remove instance [-]"); item.sprite_id = 5; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_FEWER; if (!m_toolbar.add_item(item)) return false; @@ -6279,7 +5792,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "splitobjects"; item.tooltip = GUI::L_str("Split to objects"); item.sprite_id = 6; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_SPLIT_OBJECTS; if (!m_toolbar.add_item(item)) return false; @@ -6287,7 +5799,6 @@ bool GLCanvas3D::_init_toolbar() item.name = "splitvolumes"; item.tooltip = GUI::L_str("Split to parts"); item.sprite_id = 8; - item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_SPLIT_VOLUMES; if (!m_toolbar.add_item(item)) return false; @@ -6399,8 +5910,9 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) BoundingBoxf3 GLCanvas3D::_max_bounding_box() const { - BoundingBoxf3 bb = m_bed.get_bounding_box(); - bb.merge(volumes_bounding_box()); + BoundingBoxf3 bb = volumes_bounding_box(); + if (m_bed != nullptr) + bb.merge(m_bed->get_bounding_box()); return bb; } @@ -6416,11 +5928,7 @@ void GLCanvas3D::_zoom_to_bounding_box(const BoundingBoxf3& bbox) viewport_changed(); -#if ENABLE_REWORKED_BED_SHAPE_CHANGE m_dirty = true; -#else - _refresh_if_shown_on_screen(); -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE } } @@ -6500,17 +6008,9 @@ void GLCanvas3D::_refresh_if_shown_on_screen() // Because of performance problems on macOS, where PaintEvents are not delivered // frequently enough, we call render() here directly when we can. -#if ENABLE_REWORKED_BED_SHAPE_CHANGE render(); -#else - // We can't do that when m_force_zoom_to_bed_enabled == true, because then render() - // ends up calling back here via _force_zoom_to_bed(), causing a stack overflow. - if (m_canvas != nullptr) { - m_force_zoom_to_bed_enabled ? m_canvas->Refresh() : render(); } -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE } -} void GLCanvas3D::_camera_tranform() const { @@ -6617,16 +6117,14 @@ void GLCanvas3D::_render_bed(float theta) const scale_factor = m_retina_helper->get_scale_factor(); #endif -#if ENABLE_PRINT_BED_MODELS - m_bed.render(theta, m_use_VBOs, scale_factor); -#else - m_bed.render(theta, scale_factor); -#endif // ENABLE_PRINT_BED_MODELS + if (m_bed != nullptr) + m_bed->render(theta, m_use_VBOs, scale_factor); } void GLCanvas3D::_render_axes() const { - m_axes.render(); + if (m_bed != nullptr) + m_bed->render_axes(); } void GLCanvas3D::_render_objects() const @@ -6644,9 +6142,9 @@ void GLCanvas3D::_render_objects() const // Update the layer editing selection to the first object selected, update the current object maximum Z. const_cast(m_layers_editing).select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1); - if (m_config != nullptr) + if ((m_config != nullptr) && (m_bed != nullptr)) { - const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(); + const BoundingBoxf3& bed_bb = m_bed->get_bounding_box(); m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height")); m_volumes.check_outside_state(m_config, nullptr); } @@ -6668,7 +6166,9 @@ void GLCanvas3D::_render_objects() const m_layers_editing.render_volumes(*this, this->m_volumes); } else { // do not cull backfaces to show broken geometry, if any - m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled); + m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled, [this](const GLVolume& volume) { + return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); + }); } m_volumes.render_VBOs(GLVolumeCollection::Transparent, false); m_shader.stop_using(); @@ -6684,7 +6184,9 @@ void GLCanvas3D::_render_objects() const } // do not cull backfaces to show broken geometry, if any - m_volumes.render_legacy(GLVolumeCollection::Opaque, m_picking_enabled); + m_volumes.render_legacy(GLVolumeCollection::Opaque, m_picking_enabled, [this](const GLVolume& volume) { + return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); + }); m_volumes.render_legacy(GLVolumeCollection::Transparent, false); if (m_use_clipping_planes) @@ -6718,9 +6220,6 @@ void GLCanvas3D::_render_selection_center() const void GLCanvas3D::_render_warning_texture() const { - if (!m_warning_texture_enabled) - return; - m_warning_texture.render(*this); } @@ -6765,7 +6264,7 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const ::glColor4fv(vol->render_color); } - if (!fake_colors || !vol->disabled) + if ((!fake_colors || !vol->disabled) && (vol->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) vol->render(); ++volume_id; @@ -6916,20 +6415,20 @@ void GLCanvas3D::_render_sla_slices() const { // calculate model bottom cap if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size())) - bottom_obj_triangles = triangulate_expolygons_3df(model_slices[it_min_z->second.model_slices_idx], min_z, true); + bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true); // calculate support bottom cap if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size())) - bottom_sup_triangles = triangulate_expolygons_3df(support_slices[it_min_z->second.support_slices_idx], min_z, true); + bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true); } if (it_max_z != index.end()) { // calculate model top cap if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size())) - top_obj_triangles = triangulate_expolygons_3df(model_slices[it_max_z->second.model_slices_idx], max_z, false); + top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false); // calculate support top cap if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size())) - top_sup_triangles = triangulate_expolygons_3df(support_slices[it_max_z->second.support_slices_idx], max_z, false); + top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false); } } @@ -7042,11 +6541,7 @@ void GLCanvas3D::_update_gizmos_data() m_gizmos.set_rotation(Vec3d::Zero()); ModelObject* model_object = m_model->objects[m_selection.get_object_idx()]; m_gizmos.set_flattening_data(model_object); -#if ENABLE_SLA_SUPPORT_GIZMO_MOD m_gizmos.set_sla_support_data(model_object, m_selection); -#else - m_gizmos.set_model_object_ptr(model_object); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD } else if (m_selection.is_single_volume() || m_selection.is_single_modifier()) { @@ -7054,22 +6549,14 @@ void GLCanvas3D::_update_gizmos_data() m_gizmos.set_scale(volume->get_volume_scaling_factor()); m_gizmos.set_rotation(Vec3d::Zero()); m_gizmos.set_flattening_data(nullptr); -#if ENABLE_SLA_SUPPORT_GIZMO_MOD m_gizmos.set_sla_support_data(nullptr, m_selection); -#else - m_gizmos.set_model_object_ptr(nullptr); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD } else { m_gizmos.set_scale(Vec3d::Ones()); m_gizmos.set_rotation(Vec3d::Zero()); m_gizmos.set_flattening_data(m_selection.is_from_single_object() ? m_model->objects[m_selection.get_object_idx()] : nullptr); -#if ENABLE_SLA_SUPPORT_GIZMO_MOD m_gizmos.set_sla_support_data(nullptr, m_selection); -#else - m_gizmos.set_model_object_ptr(nullptr); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD } } @@ -8272,18 +7759,8 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state() void GLCanvas3D::_show_warning_texture_if_needed() { _set_current(); - - if (_is_any_volume_outside()) - { - enable_warning_texture(true); - _generate_warning_texture(L("Detected toolpath outside print volume")); + _set_warning_texture(WarningTexture::ToolpathOutside, _is_any_volume_outside()); } - else - { - enable_warning_texture(false); - _reset_warning_texture(); - } -} std::vector GLCanvas3D::_parse_colors(const std::vector& colors) { @@ -8315,14 +7792,9 @@ void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, m_legend_texture.generate(preview_data, tool_colors, *this, m_dynamic_background_enabled && _is_any_volume_outside()); } -void GLCanvas3D::_generate_warning_texture(const std::string& msg) +void GLCanvas3D::_set_warning_texture(WarningTexture::Warning warning, bool state) { - m_warning_texture.generate(msg, *this); -} - -void GLCanvas3D::_reset_warning_texture() -{ - m_warning_texture.reset(); + m_warning_texture.activate(warning, state, *this); } bool GLCanvas3D::_is_any_volume_outside() const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d4d51bd5c..06fda3e5c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -8,6 +8,7 @@ #include "3DScene.hpp" #include "GLToolbar.hpp" #include "Event.hpp" +#include "3DBed.hpp" #include @@ -25,9 +26,6 @@ class wxGLCanvas; // Support for Retina OpenGL on Mac OS #define ENABLE_RETINA_GL __APPLE__ -class GLUquadric; -typedef class GLUquadric GLUquadricObj; - namespace Slic3r { class GLShader; @@ -45,21 +43,6 @@ class GLGizmoBase; class RetinaHelper; #endif -class GeometryBuffer -{ - std::vector m_vertices; - std::vector m_tex_coords; - -public: - bool set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords); - bool set_from_lines(const Lines& lines, float z); - - const float* get_vertices() const; - const float* get_tex_coords() const; - - unsigned int get_vertices_count() const; -}; - class Size { int m_width; @@ -131,6 +114,24 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent); + +// this describes events being passed from GLCanvas3D to SlaSupport gizmo +enum class SLAGizmoEventType { + LeftDown = 1, + LeftUp, + RightDown, + Dragging, + Delete, + SelectAll, + ShiftUp, + ApplyChanges, + DiscardChanges, + AutomaticGeneration, + ManualEditing +}; + class GLCanvas3D { @@ -196,97 +197,7 @@ class GLCanvas3D void set_scene_box(const BoundingBoxf3& box, GLCanvas3D& canvas); }; - class Bed - { - public: - /*enum EType : unsigned char - { - MK2, - MK3, - SL1, - Custom, - Num_Types - };*/ - - private: - std::string m_type; - Pointfs m_shape; - BoundingBoxf3 m_bounding_box; - Polygon m_polygon; - GeometryBuffer m_triangles; - GeometryBuffer m_gridlines; - mutable GLTexture m_top_texture; - mutable GLTexture m_bottom_texture; -#if ENABLE_PRINT_BED_MODELS - mutable GLBed m_model; -#endif // ENABLE_PRINT_BED_MODELS - - mutable float m_scale_factor; - - public: - Bed(); - -#if ENABLE_REWORKED_BED_SHAPE_CHANGE - std::string get_type() const { return m_type; } -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE - - bool is_prusa() const; - bool is_custom() const; - - const Pointfs& get_shape() const; - // Return true if the bed shape changed, so the calee will update the UI. - bool set_shape(const Pointfs& shape); - - const BoundingBoxf3& get_bounding_box() const; - bool contains(const Point& point) const; - Point point_projection(const Point& point) const; - -#if ENABLE_PRINT_BED_MODELS - void render(float theta, bool useVBOs, float scale_factor) const; -#else - void render(float theta, float scale_factor) const; -#endif // ENABLE_PRINT_BED_MODELS - - private: - void _calc_bounding_box(); - void _calc_triangles(const ExPolygon& poly); - void _calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); -#if ENABLE_REWORKED_BED_SHAPE_CHANGE - std::string _detect_type(const Pointfs& shape) const; -#else - std::string _detect_type() const; -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE -#if ENABLE_PRINT_BED_MODELS - void _render_prusa(const std::string &key, float theta, bool useVBOs) const; - void _render_custom(const std::string &key, float theta, bool useVBOs) const; -#else - void _render_prusa(const std::string &key, float theta) const; - void _render_custom(const std::string &key, float theta) const; -#endif // ENABLE_PRINT_BED_MODELS - void _render_default() const; -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - static bool _are_equal(const Pointfs& bed_1, const Pointfs& bed_2); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - }; - - struct Axes - { - static const double Radius; - static const double ArrowBaseRadius; - static const double ArrowLength; - Vec3d origin; - Vec3d length; - GLUquadricObj* m_quadric; - - Axes(); - ~Axes(); - - void render() const; - - private: - void render_axis(double length) const; - }; - +#if !ENABLE_TEXTURES_FROM_SVG class Shader { GLShader* m_shader; @@ -310,6 +221,7 @@ class GLCanvas3D private: void _reset(); }; +#endif // !ENABLE_TEXTURES_FROM_SVG class LayersEditing { @@ -463,6 +375,59 @@ class GLCanvas3D }; public: + class TransformationType + { + public: + enum Enum { + // Transforming in a world coordinate system + World = 0, + // Transforming in a local coordinate system + Local = 1, + // Absolute transformations, allowed in local coordinate system only. + Absolute = 0, + // Relative transformations, allowed in both local and world coordinate system. + Relative = 2, + // For group selection, the transformation is performed as if the group made a single solid body. + Joint = 0, + // For group selection, the transformation is performed on each object independently. + Independent = 4, + + World_Relative_Joint = World | Relative | Joint, + World_Relative_Independent = World | Relative | Independent, + Local_Absolute_Joint = Local | Absolute | Joint, + Local_Absolute_Independent = Local | Absolute | Independent, + Local_Relative_Joint = Local | Relative | Joint, + Local_Relative_Independent = Local | Relative | Independent, + }; + + TransformationType() : m_value(World) {} + TransformationType(Enum value) : m_value(value) {} + TransformationType& operator=(Enum value) { m_value = value; return *this; } + + Enum operator()() const { return m_value; } + bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; } + + void set_world() { this->remove(Local); } + void set_local() { this->add(Local); } + void set_absolute() { this->remove(Relative); } + void set_relative() { this->add(Relative); } + void set_joint() { this->remove(Independent); } + void set_independent() { this->add(Independent); } + + bool world() const { return ! this->has(Local); } + bool local() const { return this->has(Local); } + bool absolute() const { return ! this->has(Relative); } + bool relative() const { return this->has(Relative); } + bool joint() const { return ! this->has(Independent); } + bool independent() const { return this->has(Independent); } + + private: + void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); } + void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); } + + Enum m_value; + }; + class Selection { public: @@ -641,7 +606,7 @@ public: void start_dragging(); void translate(const Vec3d& displacement, bool local = false); - void rotate(const Vec3d& rotation, bool local); + void rotate(const Vec3d& rotation, TransformationType transformation_type); void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, bool local); void mirror(Axis axis); @@ -790,12 +755,8 @@ private: void set_flattening_data(const ModelObject* model_object); -#if ENABLE_SLA_SUPPORT_GIZMO_MOD void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection); -#else - void set_model_object_ptr(ModelObject* model_object); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD - void clicked_on_object(const Vec2d& mouse_position); + bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false); void delete_current_grabber(bool delete_all = false); void render_current_gizmo(const Selection& selection) const; @@ -837,18 +798,32 @@ private: class WarningTexture : public GUI::GLTexture { + public: + WarningTexture(); + + enum Warning { + ObjectOutside, + ToolpathOutside, + SomethingNotShown + }; + + // Sets a warning of the given type to be active/inactive. If several warnings are active simultaneously, + // only the last one is shown (decided by the order in the enum above). + void activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas); + void render(const GLCanvas3D& canvas) const; + + private: static const unsigned char Background_Color[3]; static const unsigned char Opacity; int m_original_width; int m_original_height; - public: - WarningTexture(); + // Information about which warnings are currently active. + std::vector m_warnings; - bool generate(const std::string& msg, const GLCanvas3D& canvas); - - void render(const GLCanvas3D& canvas) const; + // Generates the texture with given text. + bool _generate(const std::string& msg, const GLCanvas3D& canvas); }; class LegendTexture : public GUI::GLTexture @@ -886,8 +861,7 @@ private: WarningTexture m_warning_texture; wxTimer m_timer; Camera m_camera; - Bed m_bed; - Axes m_axes; + Bed3D* m_bed; LayersEditing m_layers_editing; Shader m_shader; Mouse m_mouse; @@ -909,11 +883,7 @@ private: bool m_dirty; bool m_initialized; bool m_use_VBOs; -#if ENABLE_REWORKED_BED_SHAPE_CHANGE bool m_requires_zoom_to_bed; -#else - bool m_force_zoom_to_bed_enabled; -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE bool m_apply_zoom_to_volumes_filter; mutable int m_hover_volume_id; bool m_toolbar_action_running; @@ -925,6 +895,8 @@ private: bool m_multisample_allowed; bool m_regenerate_volumes; bool m_moving; + bool m_tab_down; + bool m_render_sla_auxiliaries; std::string m_color_by; @@ -945,6 +917,8 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas; } const wxGLCanvas* get_wxglcanvas() const { return m_canvas; } + void set_bed(Bed3D* bed) { m_bed = bed; } + void set_view_toolbar(GLToolbar* toolbar) { m_view_toolbar = toolbar; } bool init(bool useVBOs, bool use_legacy_opengl); @@ -956,6 +930,9 @@ public: void reset_volumes(); int check_volumes_outside_state() const; + void toggle_sla_auxiliaries_visibility(bool visible); + void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); + void set_config(const DynamicPrintConfig* config); void set_process(BackgroundSlicingProcess* process); void set_model(Model* model); @@ -963,12 +940,7 @@ public: const Selection& get_selection() const { return m_selection; } Selection& get_selection() { return m_selection; } - // Set the bed shape to a single closed 2D polygon(array of two element arrays), - // triangulate the bed and store the triangles into m_bed.m_triangles, - // fills the m_bed.m_grid_lines and sets m_bed.m_origin. - // Sets m_bed.m_polygon to limit the object placement. - void set_bed_shape(const Pointfs& shape); - void set_bed_axes_length(double length); + void bed_shape_changed(); void set_clipping_plane(unsigned int id, const ClippingPlane& plane) { @@ -993,15 +965,11 @@ public: bool is_reload_delayed() const; void enable_layers_editing(bool enable); - void enable_warning_texture(bool enable); void enable_legend_texture(bool enable); void enable_picking(bool enable); void enable_moving(bool enable); void enable_gizmos(bool enable); void enable_toolbar(bool enable); -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - void enable_force_zoom_to_bed(bool enable); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE void enable_dynamic_background(bool enable); void allow_multisample(bool allow); @@ -1052,6 +1020,7 @@ public: void on_size(wxSizeEvent& evt); void on_idle(wxIdleEvent& evt); void on_char(wxKeyEvent& evt); + void on_key(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); @@ -1086,9 +1055,6 @@ public: private: bool _is_shown_on_screen() const; -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - void _force_zoom_to_bed(); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE bool _init_toolbar(); @@ -1178,8 +1144,7 @@ private: void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); // generates a warning texture containing the given message - void _generate_warning_texture(const std::string& msg); - void _reset_warning_texture(); + void _set_warning_texture(WarningTexture::Warning warning, bool state); bool _is_any_volume_outside() const; diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 8f2e5b219..71299f777 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -233,7 +233,7 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) attribList[4] = 0; } - return new wxGLCanvas(parent, wxID_ANY, attribList); + return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); } GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 1660976a1..7a64e5f45 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -7,7 +7,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Geometry.hpp" #include "libslic3r/Utils.hpp" -#include "libslic3r/SLA/SLASupportTree.hpp" +#include "libslic3r/SLA/SLACommon.hpp" #include "libslic3r/SLAPrint.hpp" #include @@ -25,6 +25,8 @@ #include "GUI.hpp" #include "GUI_Utils.hpp" #include "GUI_App.hpp" +#include "GUI_ObjectSettings.hpp" +#include "GUI_ObjectList.hpp" #include "I18N.hpp" #include "PresetBundle.hpp" @@ -1445,8 +1447,8 @@ void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); ::glPushMatrix(); - ::glMultMatrixd(m.data()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); + ::glMultMatrixd(m.data()); if (this->is_plane_update_necessary()) const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) @@ -1479,8 +1481,8 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); ::glPushMatrix(); - ::glMultMatrixd(m.data()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); + ::glMultMatrixd(m.data()); if (this->is_plane_update_necessary()) const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) @@ -1514,7 +1516,7 @@ void GLGizmoFlatten::update_planes() TriangleMesh ch; for (const ModelVolume* vol : m_model_object->volumes) { - if (vol->type() != ModelVolume::Type::MODEL_PART) + if (vol->type() != ModelVolumeType::MODEL_PART) continue; TriangleMesh vol_ch = vol->get_convex_hull(); vol_ch.transform(vol->get_matrix()); @@ -1741,28 +1743,20 @@ Vec3d GLGizmoFlatten::get_flattening_normal() const } GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent) -#if ENABLE_SLA_SUPPORT_GIZMO_MOD : GLGizmoBase(parent), m_starting_center(Vec3d::Zero()), m_quadric(nullptr) -#else - : GLGizmoBase(parent), m_starting_center(Vec3d::Zero()) -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD { -#if ENABLE_SLA_SUPPORT_GIZMO_MOD m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) // using GLU_FILL does not work when the instance's transformation // contains mirroring (normals are reverted) ::gluQuadricDrawStyle(m_quadric, GLU_FILL); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD } -#if ENABLE_SLA_SUPPORT_GIZMO_MOD GLGizmoSlaSupports::~GLGizmoSlaSupports() { if (m_quadric != nullptr) ::gluDeleteQuadric(m_quadric); } -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD bool GLGizmoSlaSupports::on_init() { @@ -1782,7 +1776,6 @@ bool GLGizmoSlaSupports::on_init() return true; } -#if ENABLE_SLA_SUPPORT_GIZMO_MOD void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection) { m_starting_center = Vec3d::Zero(); @@ -1791,217 +1784,165 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G if (selection.is_empty()) m_old_instance_id = -1; - if ((model_object != nullptr) && selection.is_from_single_instance()) + m_active_instance = selection.get_instance_idx(); + + if (model_object && selection.is_from_single_instance()) { if (is_mesh_update_necessary()) update_mesh(); - // If there are no points, let's ask the backend if it calculated some. - if (model_object->sla_support_points.empty() && m_parent.sla_print()->is_step_done(slaposSupportPoints)) { - for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - if (po->model_object()->id() == model_object->id()) { - const Eigen::MatrixXd& points = po->get_support_points(); - for (unsigned int i=0; isla_support_points.push_back(Vec3f(po->trafo().inverse().cast() * Vec3f(points(i,0), points(i,1), points(i,2)))); - break; - } - } + if (m_model_object != m_old_model_object) + m_editing_mode = false; + + if (m_editing_mode_cache.empty() && m_model_object->sla_points_status != sla::PointsStatus::UserModified) + get_data_from_backend(); + + if (m_state == On) { + m_parent.toggle_model_objects_visibility(false); + m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); } } } -#else -void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object) -{ - if (model_object != nullptr) { - m_starting_center = Vec3d::Zero(); - m_model_object = model_object; - - int selected_instance = m_parent.get_selection().get_instance_idx(); - assert(selected_instance < (int)model_object->instances.size()); - - m_instance_matrix = model_object->instances[selected_instance]->get_matrix(); - if (is_mesh_update_necessary()) - update_mesh(); - } -} -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const { ::glEnable(GL_BLEND); ::glEnable(GL_DEPTH_TEST); -#if !ENABLE_SLA_SUPPORT_GIZMO_MOD - // the dragged_offset is a vector measuring where was the object moved - // with the gizmo being on. This is reset in set_model_object_ptr and - // does not work correctly when there are multiple copies. - - if (m_starting_center == Vec3d::Zero()) - m_starting_center = selection.get_bounding_box().center(); - Vec3d dragged_offset = selection.get_bounding_box().center() - m_starting_center; -#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD - - - for (auto& g : m_grabbers) { - g.color[0] = 1.f; - g.color[1] = 0.f; - g.color[2] = 0.f; - } - -#if ENABLE_SLA_SUPPORT_GIZMO_MOD - render_grabbers(selection, false); -#else - //::glTranslatef((GLfloat)dragged_offset(0), (GLfloat)dragged_offset(1), (GLfloat)dragged_offset(2)); - render_grabbers(false); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD + render_points(selection, false); + render_selection_rectangle(); #if !ENABLE_IMGUI render_tooltip_texture(); #endif // not ENABLE_IMGUI + ::glDisable(GL_BLEND); } +void GLGizmoSlaSupports::render_selection_rectangle() const +{ + if (!m_selection_rectangle_active) + return; + + ::glLineWidth(1.5f); + float render_color[3] = {1.f, 0.f, 0.f}; + ::glColor3fv(render_color); + + ::glPushAttrib(GL_TRANSFORM_BIT); // remember current MatrixMode + + ::glMatrixMode(GL_MODELVIEW); // cache modelview matrix and set to identity + ::glPushMatrix(); + ::glLoadIdentity(); + + ::glMatrixMode(GL_PROJECTION); // cache projection matrix and set to identity + ::glPushMatrix(); + ::glLoadIdentity(); + + ::glOrtho(0.f, m_canvas_width, m_canvas_height, 0.f, -1.f, 1.f); // set projection matrix so that world coords = window coords + + // render the selection rectangle (window coordinates): + ::glPushAttrib(GL_ENABLE_BIT); + ::glLineStipple(4, 0xAAAA); + ::glEnable(GL_LINE_STIPPLE); + + ::glBegin(GL_LINE_LOOP); + ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); + ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); + ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); + ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); + ::glEnd(); + ::glPopAttrib(); + + ::glPopMatrix(); // restore former projection matrix + ::glMatrixMode(GL_MODELVIEW); + ::glPopMatrix(); // restore former modelview matrix + ::glPopAttrib(); // restore former MatrixMode +} void GLGizmoSlaSupports::on_render_for_picking(const GLCanvas3D::Selection& selection) const { ::glEnable(GL_DEPTH_TEST); - for (unsigned int i=0; iget_sla_shift_z(); - - ::glPushMatrix(); - ::glTranslated(0.0, 0.0, z_shift); - - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - ::glMultMatrixd(m.data()); - if (!picking) ::glEnable(GL_LIGHTING); + const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); + double z_shift = vol->get_sla_shift_z(); + const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); + const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); + + ::glPushMatrix(); + ::glTranslated(0.0, 0.0, z_shift); + ::glMultMatrixd(instance_matrix.data()); + float render_color[3]; - for (int i = 0; i < (int)m_grabbers.size(); ++i) + for (int i = 0; i < (int)m_editing_mode_cache.size(); ++i) { - // first precalculate the grabber position in world coordinates, so that the grabber - // is not scaled with the object (as it would be if rendered with current gl matrix). - Eigen::Matrix glmatrix; - glGetFloatv (GL_MODELVIEW_MATRIX, glmatrix.data()); - Eigen::Matrix grabber_pos; - for (int j=0; j<3; ++j) - grabber_pos(j) = m_grabbers[i].center(j); - grabber_pos[3] = 1.f; - Eigen::Matrix grabber_world_position = glmatrix * grabber_pos; + const sla::SupportPoint& support_point = m_editing_mode_cache[i].first; + const bool& point_selected = m_editing_mode_cache[i].second; - if (!picking && (m_hover_id == i)) - { - render_color[0] = 1.0f - m_grabbers[i].color[0]; - render_color[1] = 1.0f - m_grabbers[i].color[1]; - render_color[2] = 1.0f - m_grabbers[i].color[2]; + // First decide about the color of the point. + if (picking) { + render_color[0] = 1.0f; + render_color[1] = 1.0f; + render_color[2] = picking_color_component(i); + } + else { + if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active + render_color[0] = 0.f; + render_color[1] = 1.0f; + render_color[2] = 1.0f; + } + else { // neigher hover nor picking + bool supports_new_island = m_lock_unique_islands && m_editing_mode_cache[i].first.is_new_island; + if (m_editing_mode) { + render_color[0] = point_selected ? 1.0f : (supports_new_island ? 0.3f : 0.7f); + render_color[1] = point_selected ? 0.3f : (supports_new_island ? 0.3f : 0.7f); + render_color[2] = point_selected ? 0.3f : (supports_new_island ? 1.0f : 0.7f); + } + else + for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f; + } } - else - ::memcpy((void*)render_color, (const void*)m_grabbers[i].color, 3 * sizeof(float)); - ::glColor3fv(render_color); + float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f}; + ::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive); + + // Now render the sphere. Inverse matrix of the instance scaling is applied so that the + // sphere does not scale with the object. ::glPushMatrix(); - ::glLoadIdentity(); - ::glTranslated(grabber_world_position(0), grabber_world_position(1), grabber_world_position(2) + z_shift); - const float diameter = 0.8f; - ::gluSphere(m_quadric, diameter/2.f, 64, 36); + ::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2)); + ::glMultMatrixd(instance_scaling_matrix_inverse.data()); + ::gluSphere(m_quadric, m_editing_mode_cache[i].first.head_front_radius * RenderPointScale, 64, 36); ::glPopMatrix(); } + { + // Reset emissive component to zero (the default value) + float render_color_emissive[4] = { 0.f, 0.f, 0.f, 1.f }; + ::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive); + } + if (!picking) ::glDisable(GL_LIGHTING); ::glPopMatrix(); } -#else -void GLGizmoSlaSupports::render_grabbers(bool picking) const -{ - if (m_parent.get_selection().is_empty()) - return; - - float z_shift = m_parent.get_selection().get_volume(0)->get_sla_shift_z(); - ::glTranslatef((GLfloat)0, (GLfloat)0, (GLfloat)z_shift); - - int selected_instance = m_parent.get_selection().get_instance_idx(); - assert(selected_instance < (int)m_model_object->instances.size()); - - float render_color_inactive[3] = { 0.5f, 0.5f, 0.5f }; - - for (const ModelInstance* inst : m_model_object->instances) { - bool active = inst == m_model_object->instances[selected_instance]; - if (picking && ! active) - continue; - for (int i = 0; i < (int)m_grabbers.size(); ++i) - { - if (!m_grabbers[i].enabled) - continue; - - float render_color[3]; - if (! picking && active && m_hover_id == i) { - render_color[0] = 1.0f - m_grabbers[i].color[0]; - render_color[1] = 1.0f - m_grabbers[i].color[1]; - render_color[2] = 1.0f - m_grabbers[i].color[2]; - } - else - ::memcpy((void*)render_color, active ? (const void*)m_grabbers[i].color : (const void*)render_color_inactive, 3 * sizeof(float)); - if (!picking) - ::glEnable(GL_LIGHTING); - ::glColor3f((GLfloat)render_color[0], (GLfloat)render_color[1], (GLfloat)render_color[2]); - ::glPushMatrix(); - Vec3d center = inst->get_matrix() * m_grabbers[i].center; - ::glTranslatef((GLfloat)center(0), (GLfloat)center(1), (GLfloat)center(2)); - GLUquadricObj *quadric; - quadric = ::gluNewQuadric(); - ::gluQuadricDrawStyle(quadric, GLU_FILL ); - ::gluSphere( quadric , 0.4, 64 , 32 ); - ::gluDeleteQuadric(quadric); - ::glPopMatrix(); - if (!picking) - ::glDisable(GL_LIGHTING); - } - } - - ::glTranslatef((GLfloat)0, (GLfloat)0, (GLfloat)-z_shift); -} -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD bool GLGizmoSlaSupports::is_mesh_update_necessary() const { -#if ENABLE_SLA_SUPPORT_GIZMO_MOD - return (m_state == On) && (m_model_object != nullptr) && (m_model_object != m_old_model_object) && !m_model_object->instances.empty(); -#else - return m_state == On && m_model_object && !m_model_object->instances.empty() && !m_instance_matrix.isApprox(m_source_data.matrix); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD + return (m_state == On) && (m_model_object != m_old_model_object) && (m_model_object != nullptr) && !m_model_object->instances.empty(); //if (m_state != On || !m_model_object || m_model_object->instances.empty() || ! m_instance_matrix.isApprox(m_source_data.matrix)) // return false; - - // following should detect direct mesh changes (can be removed after the mesh is made completely immutable): - /*const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex(); - Vec3d first_point((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]); - if (first_point != m_source_data.mesh_first_point) - return true;*/ } void GLGizmoSlaSupports::update_mesh() @@ -2027,27 +1968,14 @@ void GLGizmoSlaSupports::update_mesh() m_AABB = igl::AABB(); m_AABB.init(m_V, m_F); -#if !ENABLE_SLA_SUPPORT_GIZMO_MOD - m_source_data.matrix = m_instance_matrix; -#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD - - // we'll now reload Grabbers (selection might have changed): - m_grabbers.clear(); - - for (const Vec3f& point : m_model_object->sla_support_points) { - m_grabbers.push_back(Grabber()); - m_grabbers.back().center = point.cast(); - } + // we'll now reload support points (selection might have changed): + editing_mode_reload_cache(); } Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: -#if ENABLE_SLA_SUPPORT_GIZMO_MOD if (m_V.size() == 0) -#else - if (m_V.size() == 0 || is_mesh_update_necessary()) -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD update_mesh(); Eigen::Matrix viewport; @@ -2064,20 +1992,15 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) igl::Hit hit; -#if ENABLE_SLA_SUPPORT_GIZMO_MOD const GLCanvas3D::Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); double z_offset = volume->get_sla_shift_z(); -#else - double z_offset = m_parent.get_selection().get_volume(0)->get_sla_shift_z(); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD + point1(2) -= z_offset; point2(2) -= z_offset; -#if ENABLE_SLA_SUPPORT_GIZMO_MOD + Transform3d inv = volume->get_instance_transformation().get_matrix().inverse(); -#else - Transform3d inv = m_instance_matrix.inverse(); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD + point1 = inv * point1; point2 = inv * point2; @@ -2089,68 +2012,199 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) return bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)); } -void GLGizmoSlaSupports::clicked_on_object(const Vec2d& mouse_position) +// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. +// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is +// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo +// concludes that the event was not intended for it, it should return false. +bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down) { -#if ENABLE_SLA_SUPPORT_GIZMO_MOD - int instance_id = m_parent.get_selection().get_instance_idx(); - if (m_old_instance_id != instance_id) - { - bool something_selected = (m_old_instance_id != -1); - m_old_instance_id = instance_id; - if (something_selected) - return; + if (m_editing_mode) { + + // left down - show the selection rectangle: + if (action == SLAGizmoEventType::LeftDown && shift_down) { + if (m_hover_id == -1) { + m_selection_rectangle_active = true; + m_selection_rectangle_start_corner = mouse_position; + m_selection_rectangle_end_corner = mouse_position; + m_canvas_width = m_parent.get_canvas_size().get_width(); + m_canvas_height = m_parent.get_canvas_size().get_height(); + } + else + select_point(m_hover_id); + + return true; + } + + // dragging the selection rectangle: + if (action == SLAGizmoEventType::Dragging && m_selection_rectangle_active) { + m_selection_rectangle_end_corner = mouse_position; + return true; + } + + // mouse up without selection rectangle - place point on the mesh: + if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle_active && !shift_down) { + if (m_ignore_up_event) { + m_ignore_up_event = false; + return false; + } + + int instance_id = m_parent.get_selection().get_instance_idx(); + if (m_old_instance_id != instance_id) + { + bool something_selected = (m_old_instance_id != -1); + m_old_instance_id = instance_id; + if (something_selected) + return false; + } + if (instance_id == -1) + return false; + + // If there is some selection, don't add new point and deselect everything instead. + if (m_selection_empty) { + Vec3f new_pos; + try { + new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case + m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), false)); + m_unsaved_changes = true; + } + catch (...) { // not clicked on object + return true; // prevents deselection of the gizmo by GLCanvas3D + } + } + else + select_point(NoPoints); + + return true; + } + + // left up with selection rectangle - select points inside the rectangle: + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp) + && m_selection_rectangle_active) { + if (action == SLAGizmoEventType::ShiftUp) + m_ignore_up_event = true; + const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); + GLint viewport[4]; + ::glGetIntegerv(GL_VIEWPORT, viewport); + GLdouble modelview_matrix[16]; + ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix); + GLdouble projection_matrix[16]; + ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix); + + const GLCanvas3D::Selection& selection = m_parent.get_selection(); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + double z_offset = volume->get_sla_shift_z(); + + // bounding box created from the rectangle corners - will take care of order of the corners + BoundingBox rectangle(Points{Point(m_selection_rectangle_start_corner.cast()), Point(m_selection_rectangle_end_corner.cast())}); + + const Transform3d& instance_matrix_no_translation = volume->get_instance_transformation().get_matrix(true); + // we'll recover current look direction from the modelview matrix (in world coords)... + Vec3f direction_to_camera(modelview_matrix[2], modelview_matrix[6], modelview_matrix[10]); + // ...and transform it to model coords. + direction_to_camera = (instance_matrix_no_translation.inverse().cast() * direction_to_camera).normalized().eval(); + + // Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh: + for (unsigned int i=0; i() * support_point.pos; + pos(2) += z_offset; + GLdouble out_x, out_y, out_z; + ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z); + out_y = m_canvas_height - out_y; + + if (rectangle.contains(Point(out_x, out_y))) { + bool is_obscured = false; + // Cast a ray in the direction of the camera and look for intersection with the mesh: + std::vector hits; + // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. + if (m_AABB.intersect_ray(m_V, m_F, support_point.pos + direction_to_camera * (support_point.head_front_radius + EPSILON), direction_to_camera, hits)) + // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. + // Also, the threshold is in mesh coordinates, not in actual dimensions. + if (hits.size() > 1 || hits.front().t > 0.001f) + is_obscured = true; + + if (!is_obscured) + select_point(i); + } + } + m_selection_rectangle_active = false; + return true; + } + + if (action == SLAGizmoEventType::Delete) { + // delete key pressed + delete_selected_points(); + return true; + } + + if (action == SLAGizmoEventType::ApplyChanges) { + editing_mode_apply_changes(); + return true; + } + + if (action == SLAGizmoEventType::DiscardChanges) { + editing_mode_discard_changes(); + return true; + } + + if (action == SLAGizmoEventType::RightDown) { + if (m_hover_id != -1) { + select_point(NoPoints); + select_point(m_hover_id); + delete_selected_points(); + return true; + } + return false; + } + + if (action == SLAGizmoEventType::SelectAll) { + select_point(AllPoints); + return true; + } } - if (instance_id == -1) - return; -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD - Vec3f new_pos; - try { - new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new grabber in that case + if (!m_editing_mode) { + if (action == SLAGizmoEventType::AutomaticGeneration) { + auto_generate(); + return true; + } + + if (action == SLAGizmoEventType::ManualEditing) { + switch_to_editing_mode(); + return true; + } } - catch (...) { return; } - m_grabbers.push_back(Grabber()); - m_grabbers.back().center = new_pos.cast(); - m_model_object->sla_support_points.push_back(new_pos); - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); - - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + return false; } -void GLGizmoSlaSupports::delete_current_grabber(bool delete_all) +void GLGizmoSlaSupports::delete_selected_points(bool force) { - if (delete_all) { - m_grabbers.clear(); - m_model_object->sla_support_points.clear(); - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); - } - else - if (m_hover_id != -1) { - m_grabbers.erase(m_grabbers.begin() + m_hover_id); - m_model_object->sla_support_points.erase(m_model_object->sla_support_points.begin() + m_hover_id); - m_hover_id = -1; - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); + for (unsigned int idx=0; idxreslice_SLA_supports(*m_model_object); + } + + select_point(NoPoints); + + //m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } void GLGizmoSlaSupports::on_update(const UpdateData& data, const GLCanvas3D::Selection& selection) { - if (m_hover_id != -1 && data.mouse_pos) { + if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].first.is_new_island || !m_lock_unique_islands)) { Vec3f new_pos; try { new_pos = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1))); } catch (...) { return; } - m_grabbers[m_hover_id].center = new_pos.cast(); - m_model_object->sla_support_points[m_hover_id] = new_pos; + m_editing_mode_cache[m_hover_id].first.pos = new_pos; + m_editing_mode_cache[m_hover_id].first.is_new_island = false; + m_unsaved_changes = true; // Do not update immediately, wait until the mouse is released. // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } @@ -2188,45 +2242,194 @@ void GLGizmoSlaSupports::render_tooltip_texture() const { #endif // not ENABLE_IMGUI +std::vector GLGizmoSlaSupports::get_config_options(const std::vector& keys) const +{ + std::vector out; + + if (!m_model_object) + return out; + + DynamicPrintConfig& object_cfg = m_model_object->config; + DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; + std::unique_ptr default_cfg = nullptr; + + for (const std::string& key : keys) { + if (object_cfg.has(key)) + out.push_back(object_cfg.option(key)); + else + if (print_cfg.has(key)) + out.push_back(print_cfg.option(key)); + else { // we must get it from defaults + if (default_cfg == nullptr) + default_cfg.reset(DynamicPrintConfig::new_from_defaults_keys(keys)); + out.push_back(default_cfg->option(key)); + } + } + + return out; +} + + + #if ENABLE_IMGUI void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection) { + if (!m_model_object) + return; + bool first_run = true; // This is a hack to redraw the button when all points are removed, // so it is not delayed until the background process finishes. RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_bg_alpha(0.5f); - m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove |/* ImGuiWindowFlags_NoResize | */ImGuiWindowFlags_NoCollapse); ImGui::PushItemWidth(100.0f); - m_imgui->text(_(L("Left mouse click - add point"))); - m_imgui->text(_(L("Right mouse click - remove point"))); - m_imgui->text(" "); - bool generate = m_imgui->button(_(L("Generate points automatically"))); - bool remove_all_clicked = m_imgui->button(_(L("Remove all points")) + (m_model_object == nullptr ? "" : " (" + std::to_string(m_model_object->sla_support_points.size())+")")); + bool force_refresh = false; + bool remove_selected = false; + bool remove_all = false; + + if (m_editing_mode) { + m_imgui->text(_(L("Left mouse click - add point"))); + m_imgui->text(_(L("Right mouse click - remove point"))); + m_imgui->text(_(L("Shift + Left (+ drag) - select point(s)"))); + m_imgui->text(" "); // vertical gap + + std::vector options = {"0.2", "0.4", "0.6", "0.8", "1.0"}; + std::stringstream ss; + ss << std::setprecision(1) << m_new_point_head_diameter; + wxString str = ss.str(); + + bool old_combo_state = m_combo_box_open; + // The combo is commented out for now, until the feature is supported by backend. + // m_combo_box_open = m_imgui->combo(_(L("Head diameter")), options, str); + force_refresh |= (old_combo_state != m_combo_box_open); + + float current_number = atof(str); + if (old_combo_state && !m_combo_box_open) // closing the combo must always change the sizes (even if the selection did not change) + for (auto& point_and_selection : m_editing_mode_cache) + if (point_and_selection.second) { + point_and_selection.first.head_front_radius = current_number / 2.f; + m_unsaved_changes = true; + } + + if (std::abs(current_number - m_new_point_head_diameter) > 0.001) { + force_refresh = true; + m_new_point_head_diameter = current_number; + } + + bool changed = m_lock_unique_islands; + m_imgui->checkbox(_(L("Lock supports under new islands")), m_lock_unique_islands); + force_refresh |= changed != m_lock_unique_islands; + + m_imgui->disabled_begin(m_selection_empty); + remove_selected = m_imgui->button(_(L("Remove selected points"))); + m_imgui->disabled_end(); + + m_imgui->disabled_begin(m_editing_mode_cache.empty()); + remove_all = m_imgui->button(_(L("Remove all points"))); + m_imgui->disabled_end(); + + m_imgui->text(" "); // vertical gap + + if (m_imgui->button(_(L("Apply changes")))) { + editing_mode_apply_changes(); + force_refresh = true; + } + ImGui::SameLine(); + bool discard_changes = m_imgui->button(_(L("Discard changes"))); + if (discard_changes) { + editing_mode_discard_changes(); + force_refresh = true; + } + } + else { // not in editing mode: + ImGui::PushItemWidth(100.0f); + m_imgui->text(_(L("Minimal points distance: "))); + ImGui::SameLine(); + + std::vector opts = get_config_options({"support_points_density_relative", "support_points_minimal_distance"}); + float density = static_cast(opts[0])->value; + float minimal_point_distance = static_cast(opts[1])->value; + + bool value_changed = ImGui::SliderFloat("", &minimal_point_distance, 0.f, 20.f, "%.f mm"); + if (value_changed) + m_model_object->config.opt("support_points_minimal_distance", true)->value = minimal_point_distance; + + m_imgui->text(_(L("Support points density: "))); + ImGui::SameLine(); + if (ImGui::SliderFloat(" ", &density, 0.f, 200.f, "%.f %%")) { + value_changed = true; + m_model_object->config.opt("support_points_density_relative", true)->value = (int)density; + } + + if (value_changed) { // Update side panel + wxGetApp().obj_settings()->UpdateAndShow(true); + wxGetApp().obj_list()->update_settings_items(); + } + + bool generate = m_imgui->button(_(L("Auto-generate points [A]"))); + + if (generate) + auto_generate(); + + m_imgui->text(""); + if (m_imgui->button(_(L("Manual editing [M]")))) + switch_to_editing_mode(); + + m_imgui->disabled_begin(m_editing_mode_cache.empty()); + remove_all = m_imgui->button(_(L("Remove all points"))); + m_imgui->disabled_end(); + + m_imgui->text(""); + + m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points (will be autogenerated)" : + (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? "Autogenerated points (no modifications)" : + (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" : + (m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS")))); + } m_imgui->end(); - if (remove_all_clicked) { - delete_current_grabber(true); + if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode + m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode); + force_refresh = true; + } + m_old_editing_state = m_editing_mode; + + if (remove_selected || remove_all) { + force_refresh = false; + m_parent.reload_scene(true); + if (remove_all) + select_point(AllPoints); + delete_selected_points(remove_all); + if (remove_all && !m_editing_mode) + editing_mode_apply_changes(); if (first_run) { first_run = false; goto RENDER_AGAIN; } } - if (remove_all_clicked || generate) { + if (force_refresh) m_parent.reload_scene(true); - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - } } #endif // ENABLE_IMGUI bool GLGizmoSlaSupports::on_is_activable(const GLCanvas3D::Selection& selection) const { - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) - && selection.is_from_single_instance(); + if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA + || !selection.is_from_single_instance()) + return false; + + // Check that none of the selected volumes is outside. + const GLCanvas3D::Selection::IndicesList& list = selection.get_volume_idxs(); + for (const auto& idx : list) + if (selection.get_volume(idx)->is_outside) + return false; + + return true; } bool GLGizmoSlaSupports::on_is_selectable() const @@ -2239,6 +2442,156 @@ std::string GLGizmoSlaSupports::on_get_name() const return L("SLA Support Points [L]"); } +void GLGizmoSlaSupports::on_set_state() +{ + if (m_state == On) { + if (is_mesh_update_necessary()) + update_mesh(); + + m_parent.toggle_model_objects_visibility(false); + if (m_model_object) + m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); + } + if (m_state == Off) { + if (m_old_state != Off) { // the gizmo was just turned Off + + if (m_model_object) { + if (m_unsaved_changes) { + wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L("Do you want to save your manually edited support points ?\n")), + _(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); + if (dlg.ShowModal() == wxID_YES) + editing_mode_apply_changes(); + else + editing_mode_discard_changes(); + } + } + + m_parent.toggle_model_objects_visibility(true); + m_editing_mode = false; // so it is not active next time the gizmo opens + m_editing_mode_cache.clear(); + } + } + m_old_state = m_state; +} + + + +void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selection) +{ + if (m_hover_id != -1) { + select_point(NoPoints); + select_point(m_hover_id); + } +} + + + +void GLGizmoSlaSupports::select_point(int i) +{ + if (i == AllPoints || i == NoPoints) { + for (auto& point_and_selection : m_editing_mode_cache) + point_and_selection.second = ( i == AllPoints ); + m_selection_empty = (i == NoPoints); + } + else { + m_editing_mode_cache[i].second = true; + m_selection_empty = false; + } +} + + + +void GLGizmoSlaSupports::editing_mode_discard_changes() +{ + m_editing_mode_cache.clear(); + for (const sla::SupportPoint& point : m_model_object->sla_support_points) + m_editing_mode_cache.push_back(std::make_pair(point, false)); + m_editing_mode = false; + m_unsaved_changes = false; +} + + + +void GLGizmoSlaSupports::editing_mode_apply_changes() +{ + // If there are no changes, don't touch the front-end. The data in the cache could have been + // taken from the backend and copying them to ModelObject would needlessly invalidate them. + if (m_unsaved_changes) { + m_model_object->sla_points_status = sla::PointsStatus::UserModified; + m_model_object->sla_support_points.clear(); + for (const std::pair& point_and_selection : m_editing_mode_cache) + m_model_object->sla_support_points.push_back(point_and_selection.first); + + // Recalculate support structures once the editing mode is left. + // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().plater()->reslice_SLA_supports(*m_model_object); + } + m_editing_mode = false; + m_unsaved_changes = false; +} + + + +void GLGizmoSlaSupports::editing_mode_reload_cache() +{ + m_editing_mode_cache.clear(); + for (const sla::SupportPoint& point : m_model_object->sla_support_points) + m_editing_mode_cache.push_back(std::make_pair(point, false)); + m_unsaved_changes = false; +} + + + +void GLGizmoSlaSupports::get_data_from_backend() +{ + for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { + if (po->model_object()->id() == m_model_object->id() && po->is_step_done(slaposSupportPoints)) { + m_editing_mode_cache.clear(); + const std::vector& points = po->get_support_points(); + auto mat = po->trafo().inverse().cast(); + for (unsigned int i=0; isla_points_status != sla::PointsStatus::UserModified) + m_model_object->sla_points_status = sla::PointsStatus::AutoGenerated; + + break; + } + } + m_unsaved_changes = false; + + // We don't copy the data into ModelObject, as this would stop the background processing. +} + + + +void GLGizmoSlaSupports::auto_generate() +{ + wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L( + "Autogeneration will erase all manually edited points.\n\n" + "Are you sure you want to do it?\n" + )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); + + if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_editing_mode_cache.empty() || dlg.ShowModal() == wxID_YES) { + m_model_object->sla_support_points.clear(); + m_model_object->sla_points_status = sla::PointsStatus::Generating; + m_editing_mode_cache.clear(); + wxGetApp().plater()->reslice_SLA_supports(*m_model_object); + } +} + + + +void GLGizmoSlaSupports::switch_to_editing_mode() +{ + editing_mode_reload_cache(); + m_editing_mode = true; +} + + + + // GLGizmoCut diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 7a55a2392..18ddbac69 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -403,7 +403,7 @@ private: // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; - std::vector m_volumes_types; + std::vector m_volumes_types; Vec3d m_first_instance_scale; Vec3d m_first_instance_mirror; @@ -437,32 +437,26 @@ protected: } }; + + class GLGizmoSlaSupports : public GLGizmoBase { private: ModelObject* m_model_object = nullptr; -#if ENABLE_SLA_SUPPORT_GIZMO_MOD ModelObject* m_old_model_object = nullptr; + int m_active_instance = -1; int m_old_instance_id = -1; -#else - Transform3d m_instance_matrix; -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD Vec3f unproject_on_mesh(const Vec2d& mouse_pos); -#if ENABLE_SLA_SUPPORT_GIZMO_MOD - GLUquadricObj* m_quadric; -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD + const float RenderPointScale = 1.f; + GLUquadricObj* m_quadric; Eigen::MatrixXf m_V; // vertices Eigen::MatrixXi m_F; // facets indices igl::AABB m_AABB; struct SourceDataSummary { -#if !ENABLE_SLA_SUPPORT_GIZMO_MOD - BoundingBoxf3 bounding_box; - Transform3d matrix; -#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD - Vec3d mesh_first_point; + Geometry::Transformation transformation; }; // This holds information to decide whether recalculation is necessary: @@ -472,14 +466,10 @@ private: public: explicit GLGizmoSlaSupports(GLCanvas3D& parent); -#if ENABLE_SLA_SUPPORT_GIZMO_MOD virtual ~GLGizmoSlaSupports(); void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection); -#else - void set_model_object_ptr(ModelObject* model_object); -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD - void clicked_on_object(const Vec2d& mouse_position); - void delete_current_grabber(bool delete_all); + bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down); + void delete_selected_points(bool force = false); private: bool on_init(); @@ -487,11 +477,8 @@ private: virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; -#if ENABLE_SLA_SUPPORT_GIZMO_MOD - void render_grabbers(const GLCanvas3D::Selection& selection, bool picking = false) const; -#else - void render_grabbers(bool picking = false) const; -#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD + void render_selection_rectangle() const; + void render_points(const GLCanvas3D::Selection& selection, bool picking = false) const; bool is_mesh_update_necessary() const; void update_mesh(); @@ -501,12 +488,44 @@ private: mutable GLTexture m_reset_texture; #endif // not ENABLE_IMGUI + bool m_lock_unique_islands = false; + bool m_editing_mode = false; // Is editing mode active? + bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes). + float m_new_point_head_diameter = 0.4f; // Size of a new point. + float m_minimal_point_distance = 20.f; + float m_density = 100.f; + std::vector> m_editing_mode_cache; // a support point and whether it is currently selected + + bool m_selection_rectangle_active = false; + Vec2d m_selection_rectangle_start_corner; + Vec2d m_selection_rectangle_end_corner; + bool m_ignore_up_event = false; + bool m_combo_box_open = false; // To ensure proper rendering of the imgui combobox. + bool m_unsaved_changes = false; // Are there unsaved changes in manual mode? + bool m_selection_empty = true; + EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) + int m_canvas_width; + int m_canvas_height; + + std::vector get_config_options(const std::vector& keys) const; + + // Methods that do the model_object and editing cache synchronization, + // editing mode selection, etc: + enum { + AllPoints = -2, + NoPoints, + }; + void select_point(int i); + void editing_mode_apply_changes(); + void editing_mode_discard_changes(); + void editing_mode_reload_cache(); + void get_data_from_backend(); + void auto_generate(); + void switch_to_editing_mode(); + protected: - void on_set_state() override { - if (m_state == On && is_mesh_update_necessary()) { - update_mesh(); - } - } + void on_set_state() override; + void on_start_dragging(const GLCanvas3D::Selection& selection) override; #if ENABLE_IMGUI virtual void on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection) override; diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 791f452ef..f401f5466 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -225,6 +225,17 @@ bool GLShader::set_uniform(const char* name, const float* matrix) const return false; } +bool GLShader::set_uniform(const char* name, int value) const +{ + int id = get_uniform_location(name); + if (id >= 0) + { + ::glUniform1i(id, value); + return true; + } + return false; +} + /* # Set shader vector sub SetVector @@ -253,4 +264,101 @@ sub SetMatrix } */ +#if ENABLE_TEXTURES_FROM_SVG +Shader::Shader() + : m_shader(nullptr) +{ +} + +Shader::~Shader() +{ + reset(); +} + +bool Shader::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename) +{ + if (is_initialized()) + return true; + + m_shader = new GLShader(); + if (m_shader != nullptr) + { + if (!m_shader->load_from_file(fragment_shader_filename.c_str(), vertex_shader_filename.c_str())) + { + std::cout << "Compilaton of shader failed:" << std::endl; + std::cout << m_shader->last_error << std::endl; + reset(); + return false; + } + } + + return true; +} + +bool Shader::is_initialized() const +{ + return (m_shader != nullptr); +} + +bool Shader::start_using() const +{ + if (is_initialized()) + { + m_shader->enable(); + return true; + } + else + return false; +} + +void Shader::stop_using() const +{ + if (m_shader != nullptr) + m_shader->disable(); +} + +int Shader::get_attrib_location(const std::string& name) const +{ + return (m_shader != nullptr) ? m_shader->get_attrib_location(name.c_str()) : -1; +} + +int Shader::get_uniform_location(const std::string& name) const +{ + return (m_shader != nullptr) ? m_shader->get_uniform_location(name.c_str()) : -1; +} + +void Shader::set_uniform(const std::string& name, float value) const +{ + if (m_shader != nullptr) + m_shader->set_uniform(name.c_str(), value); +} + +void Shader::set_uniform(const std::string& name, const float* matrix) const +{ + if (m_shader != nullptr) + m_shader->set_uniform(name.c_str(), matrix); +} + +void Shader::set_uniform(const std::string& name, bool value) const +{ + if (m_shader != nullptr) + m_shader->set_uniform(name.c_str(), value ? 1 : 0); +} + +unsigned int Shader::get_shader_program_id() const +{ + return (m_shader != nullptr) ? m_shader->shader_program_id : 0; +} + +void Shader::reset() +{ + if (m_shader != nullptr) + { + m_shader->release(); + delete m_shader; + m_shader = nullptr; + } +} +#endif // ENABLE_TEXTURES_FROM_SVG + } // namespace Slic3r diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index 0634cce6e..58e2678d0 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -26,6 +26,7 @@ public: bool set_uniform(const char *name, float value) const; bool set_uniform(const char* name, const float* matrix) const; + bool set_uniform(const char* name, int value) const; void enable() const; void disable() const; @@ -36,6 +37,37 @@ public: std::string last_error; }; +#if ENABLE_TEXTURES_FROM_SVG +class Shader +{ + GLShader* m_shader; + +public: + Shader(); + ~Shader(); + + bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename); + + bool is_initialized() const; + + bool start_using() const; + void stop_using() const; + + int get_attrib_location(const std::string& name) const; + int get_uniform_location(const std::string& name) const; + + void set_uniform(const std::string& name, float value) const; + void set_uniform(const std::string& name, const float* matrix) const; + void set_uniform(const std::string& name, bool value) const; + + const GLShader* get_shader() const { return m_shader; } + unsigned int get_shader_program_id() const; + +private: + void reset(); +}; +#endif // ENABLE_TEXTURES_FROM_SVG + } #endif /* slic3r_GLShader_hpp_ */ diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 292ef472a..19eff88e0 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -1,3 +1,4 @@ +#include "libslic3r/libslic3r.h" #include "GLTexture.hpp" #include @@ -5,10 +6,22 @@ #include #include +#if ENABLE_TEXTURES_FROM_SVG +#include +#endif // ENABLE_TEXTURES_FROM_SVG #include #include +#if ENABLE_TEXTURES_FROM_SVG +#define NANOSVG_IMPLEMENTATION +#include "nanosvg/nanosvg.h" +#define NANOSVGRAST_IMPLEMENTATION +#include "nanosvg/nanosvgrast.h" +#endif // ENABLE_TEXTURES_FROM_SVG + +#include "libslic3r/Utils.hpp" + namespace Slic3r { namespace GUI { @@ -27,7 +40,34 @@ GLTexture::~GLTexture() reset(); } -bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmaps) +#if ENABLE_TEXTURES_FROM_SVG +bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) +{ + reset(); + + if (!boost::filesystem::exists(filename)) + return false; + + if (boost::algorithm::iends_with(filename, ".png")) + return load_from_png(filename, use_mipmaps); + else + return false; +} + +bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) +{ + reset(); + + if (!boost::filesystem::exists(filename)) + return false; + + if (boost::algorithm::iends_with(filename, ".svg")) + return load_from_svg(filename, use_mipmaps, max_size_px); + else + return false; +} +#else +bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) { reset(); @@ -78,10 +118,10 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); - if (generate_mipmaps) + if (use_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards - unsigned int levels_count = _generate_mipmaps(image); + unsigned int levels_count = generate_mipmaps(image); ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count); ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } @@ -97,6 +137,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap m_source = filename; return true; } +#endif // ENABLE_TEXTURES_FROM_SVG void GLTexture::reset() { @@ -109,26 +150,6 @@ void GLTexture::reset() m_source = ""; } -unsigned int GLTexture::get_id() const -{ - return m_id; -} - -int GLTexture::get_width() const -{ - return m_width; -} - -int GLTexture::get_height() const -{ - return m_height; -} - -const std::string& GLTexture::get_source() const -{ - return m_source; -} - void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { render_sub_texture(tex_id, left, right, bottom, top, FullTextureUVs); @@ -157,7 +178,7 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, ::glDisable(GL_BLEND); } -unsigned int GLTexture::_generate_mipmaps(wxImage& image) +unsigned int GLTexture::generate_mipmaps(wxImage& image) { int w = image.GetWidth(); int h = image.GetHeight(); @@ -195,5 +216,152 @@ unsigned int GLTexture::_generate_mipmaps(wxImage& image) return (unsigned int)level; } +#if ENABLE_TEXTURES_FROM_SVG +bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps) +{ + // Load a PNG with an alpha channel. + wxImage image; + if (!image.LoadFile(wxString::FromUTF8(filename.c_str()), wxBITMAP_TYPE_PNG)) + { + reset(); + return false; + } + + m_width = image.GetWidth(); + m_height = image.GetHeight(); + int n_pixels = m_width * m_height; + + if (n_pixels <= 0) + { + reset(); + return false; + } + + // Get RGB & alpha raw data from wxImage, pack them into an array. + unsigned char* img_rgb = image.GetData(); + if (img_rgb == nullptr) + { + reset(); + return false; + } + + unsigned char* img_alpha = image.GetAlpha(); + + std::vector data(n_pixels * 4, 0); + for (int i = 0; i < n_pixels; ++i) + { + int data_id = i * 4; + int img_id = i * 3; + data[data_id + 0] = img_rgb[img_id + 0]; + data[data_id + 1] = img_rgb[img_id + 1]; + data[data_id + 2] = img_rgb[img_id + 2]; + data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255; + } + + // sends data to gpu + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glGenTextures(1, &m_id); + ::glBindTexture(GL_TEXTURE_2D, m_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); + if (use_mipmaps) + { + // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards + unsigned int levels_count = generate_mipmaps(image); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else + { + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + } + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + ::glBindTexture(GL_TEXTURE_2D, 0); + + m_source = filename; + + return true; +} + +bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) +{ + NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f); + if (image == nullptr) + { +// printf("Could not open SVG image.\n"); + reset(); + return false; + } + + float scale = (float)max_size_px / std::max(image->width, image->height); + + m_width = (int)(scale * image->width); + m_height = (int)(scale * image->height); + int n_pixels = m_width * m_height; + + if (n_pixels <= 0) + { + reset(); + return false; + } + + NSVGrasterizer* rast = nsvgCreateRasterizer(); + if (rast == nullptr) + { +// printf("Could not init rasterizer.\n"); + nsvgDelete(image); + reset(); + return false; + } + + // creates the temporary buffer only once, with max size, and reuse it for all the levels, if generating mipmaps + std::vector data(n_pixels * 4, 0); + nsvgRasterize(rast, image, 0, 0, scale, data.data(), m_width, m_height, m_width * 4); + + // sends data to gpu + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glGenTextures(1, &m_id); + ::glBindTexture(GL_TEXTURE_2D, m_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); + if (use_mipmaps) + { + // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards + int lod_w = m_width; + int lod_h = m_height; + GLint level = 0; + while ((lod_w > 1) || (lod_h > 1)) + { + ++level; + + lod_w = std::max(lod_w / 2, 1); + lod_h = std::max(lod_h / 2, 1); + scale /= 2.0f; + + nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4); + ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); + } + + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + level); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else + { + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + } + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + ::glBindTexture(GL_TEXTURE_2D, 0); + + m_source = filename; + + nsvgDeleteRasterizer(rast); + nsvgDelete(image); + + return true; +} +#endif // ENABLE_TEXTURES_FROM_SVG + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index e027bd152..af41ac342 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -37,20 +37,28 @@ namespace GUI { GLTexture(); virtual ~GLTexture(); - bool load_from_file(const std::string& filename, bool generate_mipmaps); + bool load_from_file(const std::string& filename, bool use_mipmaps); +#if ENABLE_TEXTURES_FROM_SVG + bool load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); +#endif // ENABLE_TEXTURES_FROM_SVG void reset(); - unsigned int get_id() const; - int get_width() const; - int get_height() const; + unsigned int get_id() const { return m_id; } + int get_width() const { return m_width; } + int get_height() const { return m_height; } - const std::string& get_source() const; + const std::string& get_source() const { return m_source; } static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs); protected: - unsigned int _generate_mipmaps(wxImage& image); + unsigned int generate_mipmaps(wxImage& image); +#if ENABLE_TEXTURES_FROM_SVG + private: + bool load_from_png(const std::string& filename, bool use_mipmaps); + bool load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); +#endif // ENABLE_TEXTURES_FROM_SVG }; } // namespace GUI diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 4c5d7430a..a001ad747 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -211,8 +211,10 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt } break; case coEnum:{ - if (opt_key.compare("top_fill_pattern") == 0 || opt_key.compare("bottom_fill_pattern") == 0 || - opt_key.compare("solid_fill_pattern") == 0 || opt_key.compare("fill_pattern") == 0) + if (opt_key == "top_fill_pattern" || + opt_key == "bottom_fill_pattern" || + opt_key == "solid_fill_pattern" || + opt_key == "fill_pattern") config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("gcode_flavor") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); @@ -365,21 +367,6 @@ boost::filesystem::path into_path(const wxString &str) return boost::filesystem::path(str.wx_str()); } -bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height) -{ - const auto idx = wxDisplay::GetFromWindow(window); - if (idx == wxNOT_FOUND) { - return false; - } - - wxDisplay display(idx); - const auto disp_size = display.GetClientArea(); - width = disp_size.GetWidth(); - height = disp_size.GetHeight(); - - return true; -} - void about() { AboutDialog dlg; diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index f066c82a8..4074c2afc 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -71,9 +71,6 @@ wxString from_path(const boost::filesystem::path &path); // boost path from wxString boost::filesystem::path into_path(const wxString &str); -// Returns the dimensions of the screen on which the main frame is displayed -bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height); - // Display an About dialog extern void about(); // Ask the destop to open the datadir using the default file explorer. diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index cfb10f17e..10445592b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3,8 +3,10 @@ #include "GUI_ObjectManipulation.hpp" #include "I18N.hpp" +#include #include #include +#include #include #include @@ -54,7 +56,7 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension) /* FT_INI */ "INI files (*.ini)|*.ini;*.INI", /* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG", - /* FT_PNGZIP */"Zipped PNG files (*.dwz)|*.dwz;*.DWZ", // This is lame, but that's what we use for SLA + /* FT_PNGZIP */"Masked SLA files (*.sl1)|*.sl1;*.SL1", }; std::string out = defaults[file_type]; @@ -76,6 +78,7 @@ IMPLEMENT_APP(GUI_App) GUI_App::GUI_App() : wxApp() + , m_em_unit(10) #if ENABLE_IMGUI , m_imgui(new ImGuiWrapper()) #endif // ENABLE_IMGUI @@ -125,6 +128,10 @@ bool GUI_App::OnInit() app_config->save(); preset_updater = new PresetUpdater(); + Bind(EVT_SLIC3R_VERSION_ONLINE, [this](const wxCommandEvent &evt) { + app_config->set("version_online", into_u8(evt.GetString())); + app_config->save(); + }); load_language(); @@ -154,15 +161,15 @@ bool GUI_App::OnInit() Bind(wxEVT_IDLE, [this](wxIdleEvent& event) { - if (app_config->dirty()) + if (app_config->dirty() && app_config->get("autosave") == "1") app_config->save(); // ! Temporary workaround for the correct behavior of the Scrolled sidebar panel // Do this "manipulations" only once ( after (re)create of the application ) - if (plater_ && sidebar().obj_list()->GetMinHeight() > 200) + if (plater_ && sidebar().obj_list()->GetMinHeight() > 15 * wxGetApp().em_unit()) { wxWindowUpdateLocker noUpdates_sidebar(&sidebar()); - sidebar().obj_list()->SetMinSize(wxSize(-1, 200)); + sidebar().obj_list()->SetMinSize(wxSize(-1, 15 * wxGetApp().em_unit())); // !!! to correct later layouts update_mode(); // update view mode after fix of the object_list size @@ -170,34 +177,40 @@ bool GUI_App::OnInit() if (this->plater() != nullptr) this->obj_manipul()->update_if_dirty(); - }); - // On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...) - // are shown before or in the same event callback with the main frame creation. - // Therefore we schedule them for later using CallAfter. - CallAfter([this]() { - try { - if (!preset_updater->config_update()) - mainframe->Close(); - } catch (const std::exception &ex) { - show_error(nullptr, ex.what()); - mainframe->Close(); + // Preset updating & Configwizard are done after the above initializations, + // and after MainFrame is created & shown. + // The extra CallAfter() is needed because of Mac, where this is the only way + // to popup a modal dialog on start without screwing combo boxes. + // This is ugly but I honestly found not better way to do it. + // Neither wxShowEvent nor wxWindowCreateEvent work reliably. + static bool once = true; + if (once) { + once = false; + + try { + if (!preset_updater->config_update()) { + mainframe->Close(); + } + } catch (const std::exception &ex) { + show_error(nullptr, ex.what()); + } + + CallAfter([this] { + if (!config_wizard_startup(app_conf_exists)) { + // Only notify if there was not wizard so as not to bother too much ... + preset_updater->slic3r_update_notify(); + } + preset_updater->sync(preset_bundle); + }); + + load_current_presets(); } }); - CallAfter([this]() { - if (!config_wizard_startup(app_conf_exists)) { - // Only notify if there was not wizard so as not to bother too much ... - preset_updater->slic3r_update_notify(); - } - preset_updater->sync(preset_bundle); - - load_current_presets(); - }); - - mainframe->Show(true); - return m_initialized = true; + m_initialized = true; + return true; } unsigned GUI_App::get_colour_approx_luma(const wxColour &colour) @@ -246,6 +259,7 @@ void GUI_App::init_fonts() { m_small_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); m_bold_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); + #ifdef __WXMAC__ m_small_font.SetPointSize(11); m_bold_font.SetPointSize(13); @@ -351,21 +365,10 @@ void GUI_App::persist_window_geometry(wxTopLevelWindow *window) }); window_pos_restore(window, name); -#ifdef _WIN32 - // On windows, the wxEVT_SHOW is not received if the window is created maximized - // cf. https://groups.google.com/forum/#!topic/wx-users/c7ntMt6piRI - // so we sanitize the position right away - window_pos_sanitize(window); -#else - // On other platforms on the other hand it's needed to wait before the window is actually on screen - // and some initial round of events is complete otherwise position / display index is not reported correctly. - window->Bind(wxEVT_SHOW, [=](wxShowEvent &event) { - CallAfter([=]() { - window_pos_sanitize(window); - }); - event.Skip(); + + on_window_geometry(window, [=]() { + window_pos_sanitize(window); }); -#endif } void GUI_App::load_project(wxWindow *parent, wxString& input_file) @@ -418,6 +421,7 @@ bool GUI_App::select_language( wxArrayString & names, //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); + m_imgui->set_language(m_wxLocale->GetCanonicalName().ToUTF8().data()); return true; } return false; @@ -446,6 +450,7 @@ bool GUI_App::load_language() //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); + m_imgui->set_language(m_wxLocale->GetCanonicalName().ToUTF8().data()); return true; } } @@ -573,7 +578,10 @@ void GUI_App::add_config_menu(wxMenuBar *menu) mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _(L("Simple")), _(L("Simple View Mode"))); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _(L("Advanced")), _(L("Advanced View Mode"))); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeExpert, _(L("Expert")), _(L("Expert View Mode"))); - mode_menu->Check(config_id_base + ConfigMenuModeSimple + get_mode(), true); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Check(get_mode() == comSimple); }, config_id_base + ConfigMenuModeSimple); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Check(get_mode() == comAdvanced); }, config_id_base + ConfigMenuModeAdvanced); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Check(get_mode() == comExpert); }, config_id_base + ConfigMenuModeExpert); + local_menu->AppendSubMenu(mode_menu, _(L("Mode")), _(L("Slic3r View Mode"))); local_menu->AppendSeparator(); local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application &Language"))); @@ -692,6 +700,23 @@ void GUI_App::load_current_presets() } } +bool GUI_App::OnExceptionInMainLoop() +{ + try { + throw; + } catch (const std::exception &ex) { + const std::string error = (boost::format("Uncaught exception: %1%") % ex.what()).str(); + BOOST_LOG_TRIVIAL(error) << error; + show_error(nullptr, from_u8(error)); + } catch (...) { + const char *error = "Uncaught exception: Unknown error"; + BOOST_LOG_TRIVIAL(error) << error; + show_error(nullptr, from_u8(error)); + } + + return false; +} + #ifdef __APPLE__ // wxWidgets override to get an event on open files. void GUI_App::MacOpenFiles(const wxArrayString &fileNames) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 43938b66a..4c23e3eb7 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -81,6 +81,9 @@ class GUI_App : public wxApp wxFont m_small_font; wxFont m_bold_font; + size_t m_em_unit; // width of a "m"-symbol in pixels for current system font + // Note: for 100% Scale m_em_unit = 10 -> it's a good enough coefficient for a size setting of controls + wxLocale* m_wxLocale{ nullptr }; #if ENABLE_IMGUI @@ -108,6 +111,8 @@ public: const wxFont& small_font() { return m_small_font; } const wxFont& bold_font() { return m_bold_font; } + size_t em_unit() const { return m_em_unit; } + void set_em_unit(const size_t em_unit) { m_em_unit = em_unit; } void recreate_GUI(); void system_info(); @@ -137,6 +142,8 @@ public: bool checked_tab(Tab* tab); void load_current_presets(); + virtual bool OnExceptionInMainLoop(); + #ifdef __APPLE__ // wxWidgets override to get an event on open files. void MacOpenFiles(const wxArrayString &fileNames) override; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 44cf4ae56..8a320fca2 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -45,18 +45,18 @@ ObjectList::ObjectList(wxWindow* parent) : // Fill CATEGORY_ICON { // ptFFF - CATEGORY_ICON[L("Layers and Perimeters")] = wxBitmap(from_u8(var("layers.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Infill")] = wxBitmap(from_u8(var("infill.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Support material")] = wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Speed")] = wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Extruders")] = wxBitmap(from_u8(var("funnel.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Extrusion Width")] = wxBitmap(from_u8(var("funnel.png")), wxBITMAP_TYPE_PNG); -// CATEGORY_ICON[L("Skirt and brim")] = wxBitmap(from_u8(var("box.png")), wxBITMAP_TYPE_PNG); -// CATEGORY_ICON[L("Speed > Acceleration")] = wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Advanced")] = wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers.png"); // wxBitmap(from_u8(var("layers.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill.png"); // wxBitmap(from_u8(var("infill.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("building.png"); // wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time.png"); // wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel.png"); // wxBitmap(from_u8(var("funnel.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel.png"); // wxBitmap(from_u8(var("funnel.png")), wxBITMAP_TYPE_PNG); +// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("box.png"); // wxBitmap(from_u8(var("box.png")), wxBITMAP_TYPE_PNG); +// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time.png"); // wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wand.png"); // wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG); // ptSLA - CATEGORY_ICON[L("Supports")] = wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG); - CATEGORY_ICON[L("Pad")] = wxBitmap(from_u8(var("brick.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("building.png"); // wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG); + CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("brick.png"); // wxBitmap(from_u8(var("brick.png")), wxBITMAP_TYPE_PNG); } // create control @@ -116,7 +116,7 @@ void ObjectList::create_objects_ctrl() SetMinSize(wxSize(-1, 3000)); // #ys_FIXME m_sizer = new wxBoxSizer(wxVERTICAL); - m_sizer->Add(this, 1, wxGROW | wxLEFT, 20); + m_sizer->Add(this, 1, wxGROW); m_objects_model = new PrusaObjectDataViewModel; AssociateModel(m_objects_model); @@ -129,13 +129,13 @@ void ObjectList::create_objects_ctrl() // column 0(Icon+Text) of the view control: // And Icon can be consisting of several bitmaps AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(), - 0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); + 0, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); // column 1 of the view control: AppendColumn(create_objects_list_extruder_column(4)); // column 2 of the view control: - AppendBitmapColumn(" ", 2, wxDATAVIEW_CELL_INERT, 25, + AppendBitmapColumn(" ", 2, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); } @@ -218,7 +218,8 @@ wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_ choices.Add(wxString::Format("%d", i)); wxDataViewChoiceRenderer *c = new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); - wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 1, 80, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 1, + 8*wxGetApp().em_unit()/*80*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); return column; } @@ -334,11 +335,18 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const void ObjectList::init_icons() { - m_bmp_modifiermesh = wxBitmap(from_u8(var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG); - m_bmp_solidmesh = wxBitmap(from_u8(var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG); +// m_bmp_modifiermesh = wxBitmap(from_u8(var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG); +// m_bmp_solidmesh = wxBitmap(from_u8(var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG); + +// m_bmp_support_enforcer = wxBitmap(from_u8(var("support_enforcer_.png")), wxBITMAP_TYPE_PNG); +// m_bmp_support_blocker = wxBitmap(from_u8(var("support_blocker_.png")), wxBITMAP_TYPE_PNG); + + + m_bmp_modifiermesh = create_scaled_bitmap("lambda.png"); + m_bmp_solidmesh = create_scaled_bitmap("object.png"); + m_bmp_support_enforcer = create_scaled_bitmap("support_enforcer_.png"); + m_bmp_support_blocker = create_scaled_bitmap("support_blocker_.png"); - m_bmp_support_enforcer = wxBitmap(from_u8(var("support_enforcer_.png")), wxBITMAP_TYPE_PNG); - m_bmp_support_blocker = wxBitmap(from_u8(var("support_blocker_.png")), wxBITMAP_TYPE_PNG); m_bmp_vector.reserve(4); // bitmaps for different types of parts m_bmp_vector.push_back(&m_bmp_solidmesh); // Add part @@ -348,13 +356,16 @@ void ObjectList::init_icons() m_objects_model->SetVolumeBitmaps(m_bmp_vector); // init icon for manifold warning - m_bmp_manifold_warning = wxBitmap(from_u8(var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG); +// m_bmp_manifold_warning = wxBitmap(from_u8(var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG); + m_bmp_manifold_warning = create_scaled_bitmap("exclamation_mark_.png"); // init bitmap for "Split to sub-objects" context menu - m_bmp_split = wxBitmap(from_u8(var("split.png")), wxBITMAP_TYPE_PNG); +// m_bmp_split = wxBitmap(from_u8(var("split.png")), wxBITMAP_TYPE_PNG); + m_bmp_split = create_scaled_bitmap("split.png"); // init bitmap for "Add Settings" context menu - m_bmp_cog = wxBitmap(from_u8(var("cog.png")), wxBITMAP_TYPE_PNG); +// m_bmp_cog = wxBitmap(from_u8(var("cog.png")), wxBITMAP_TYPE_PNG); + m_bmp_cog = create_scaled_bitmap("cog.png"); } @@ -807,7 +818,7 @@ void ObjectList::update_settings_item() } } -void ObjectList::append_menu_item_add_generic(wxMenuItem* menu, const int type) { +void ObjectList::append_menu_item_add_generic(wxMenuItem* menu, const ModelVolumeType type) { auto sub_menu = new wxMenu; if (wxGetApp().get_mode() == comExpert) { @@ -816,10 +827,9 @@ void ObjectList::append_menu_item_add_generic(wxMenuItem* menu, const int type) sub_menu->AppendSeparator(); } - std::vector menu_items = { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }; - for (auto& item : menu_items) { + for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }) { append_menu_item(sub_menu, wxID_ANY, _(item), "", - [this, type, item](wxCommandEvent&) { load_generic_subobject(_(item).ToUTF8().data(), type); }, "", menu->GetMenu()); + [this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu->GetMenu()); } menu->SetSubMenu(sub_menu); @@ -828,10 +838,10 @@ void ObjectList::append_menu_item_add_generic(wxMenuItem* menu, const int type) void ObjectList::append_menu_items_add_volume(wxMenu* menu) { // Note: id accords to type of the sub-object, so sequence of the menu items is important - std::vector menu_object_types_items = {L("Add part"), // ~ModelVolume::MODEL_PART - L("Add modifier"), // ~ModelVolume::PARAMETER_MODIFIER - L("Add support enforcer"), // ~ModelVolume::SUPPORT_ENFORCER - L("Add support blocker") }; // ~ModelVolume::SUPPORT_BLOCKER + std::vector menu_object_types_items = {L("Add part"), // ~ModelVolumeType::MODEL_PART + L("Add modifier"), // ~ModelVolumeType::PARAMETER_MODIFIER + L("Add support enforcer"), // ~ModelVolumeType::SUPPORT_ENFORCER + L("Add support blocker") }; // ~ModelVolumeType::SUPPORT_BLOCKER // Update "add" items(delete old & create new) settings popupmenu for (auto& item : menu_object_types_items){ @@ -845,15 +855,15 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu) if (mode < comExpert) { append_menu_item(menu, wxID_ANY, _(L("Add part")), "", - [this](wxCommandEvent&) { load_subobject(ModelVolume::MODEL_PART); }, *m_bmp_vector[ModelVolume::MODEL_PART]); + [this](wxCommandEvent&) { load_subobject(ModelVolumeType::MODEL_PART); }, *m_bmp_vector[int(ModelVolumeType::MODEL_PART)]); } if (mode == comSimple) { append_menu_item(menu, wxID_ANY, _(L("Add support enforcer")), "", - [this](wxCommandEvent&) { load_generic_subobject(_(L("Box")).ToUTF8().data(), ModelVolume::SUPPORT_ENFORCER); }, - *m_bmp_vector[ModelVolume::SUPPORT_ENFORCER]); + [this](wxCommandEvent&) { load_generic_subobject(L("Box"), ModelVolumeType::SUPPORT_ENFORCER); }, + *m_bmp_vector[int(ModelVolumeType::SUPPORT_ENFORCER)]); append_menu_item(menu, wxID_ANY, _(L("Add support blocker")), "", - [this](wxCommandEvent&) { load_generic_subobject(_(L("Box")).ToUTF8().data(), ModelVolume::SUPPORT_BLOCKER); }, - *m_bmp_vector[ModelVolume::SUPPORT_BLOCKER]); + [this](wxCommandEvent&) { load_generic_subobject(L("Box"), ModelVolumeType::SUPPORT_BLOCKER); }, + *m_bmp_vector[int(ModelVolumeType::SUPPORT_BLOCKER)]); return; } @@ -864,7 +874,7 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu) auto menu_item = new wxMenuItem(menu, wxID_ANY, _(item)); menu_item->SetBitmap(*m_bmp_vector[type]); - append_menu_item_add_generic(menu_item, type); + append_menu_item_add_generic(menu_item, ModelVolumeType(type)); menu->Append(menu_item); } @@ -913,7 +923,7 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) menu->DestroySeparators(); // delete old separators const auto sel_vol = get_selected_model_volume(); - if (sel_vol && sel_vol->type() >= ModelVolume::SUPPORT_ENFORCER) + if (sel_vol && sel_vol->type() >= ModelVolumeType::SUPPORT_ENFORCER) return nullptr; const ConfigOptionMode mode = wxGetApp().get_mode(); @@ -937,7 +947,7 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) menu_item->SetBitmap(m_bmp_cog); // const auto sel_vol = get_selected_model_volume(); -// if (sel_vol && sel_vol->type() >= ModelVolume::SUPPORT_ENFORCER) +// if (sel_vol && sel_vol->type() >= ModelVolumeType::SUPPORT_ENFORCER) // menu_item->Enable(false); // else menu_item->SetSubMenu(create_settings_popupmenu(menu)); @@ -1092,7 +1102,7 @@ void ObjectList::update_opt_keys(t_config_option_keys& opt_keys) opt_keys.erase(opt_keys.begin() + i); } -void ObjectList::load_subobject(int type) +void ObjectList::load_subobject(ModelVolumeType type) { auto item = GetSelection(); if (!item || m_objects_model->GetParent(item) != wxDataViewItem(0)) @@ -1115,7 +1125,7 @@ void ObjectList::load_subobject(int type) void ObjectList::load_part( ModelObject* model_object, wxArrayString& part_names, - int type) + ModelVolumeType type) { wxWindow* parent = wxGetApp().tab_panel()->GetPage(0); @@ -1148,7 +1158,7 @@ void ObjectList::load_part( ModelObject* model_object, #endif // !ENABLE_VOLUMES_CENTERING_FIXES volume->translate(delta); auto new_volume = model_object->add_volume(*volume); - new_volume->set_type(static_cast(type)); + new_volume->set_type(type); new_volume->name = boost::filesystem::path(input_file).filename().string(); part_names.Add(from_u8(new_volume->name)); @@ -1163,64 +1173,145 @@ void ObjectList::load_part( ModelObject* model_object, } -void ObjectList::load_generic_subobject(const std::string& type_name, const int type) +// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity +// as possible in least squares norm in regard to the 8 corners of bbox. +// Bounding box is expected to be centered around zero in all axes. +Geometry::Transformation volume_to_bed_transformation(const Geometry::Transformation &instance_transformation, const BoundingBoxf3 &bbox) +{ + Geometry::Transformation out; + + // Is the angle close to a multiple of 90 degrees? + auto ninety_degrees = [](double a) { + a = fmod(std::abs(a), 0.5 * PI); + if (a > 0.25 * PI) + a = 0.5 * PI - a; + return a < 0.001; + }; + if (instance_transformation.is_scaling_uniform()) { + // No need to run the non-linear least squares fitting for uniform scaling. + // Just set the inverse. + out.set_from_transform(instance_transformation.get_matrix(true).inverse()); + } + else if (ninety_degrees(instance_transformation.get_rotation().x()) && ninety_degrees(instance_transformation.get_rotation().y()) && ninety_degrees(instance_transformation.get_rotation().z())) + { + // Anisotropic scaling, rotation by multiples of ninety degrees. + Eigen::Matrix3d instance_rotation_trafo = + (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * + Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix(); + Eigen::Matrix3d volume_rotation_trafo = + (Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) * + Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); + + // 8 corners of the bounding box. + auto pts = Eigen::MatrixXd(8, 3); + pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z(); + pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z(); + pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z(); + pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z(); + pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z(); + pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z(); + pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z(); + pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z(); + + // Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier. + auto qs = pts * + (instance_rotation_trafo * + Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) * + volume_rotation_trafo).inverse().transpose(); + // Fill in scaling based on least squares fitting of the bounding box corners. + Vec3d scale; + for (int i = 0; i < 3; ++ i) + scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); + + out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); + out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); + out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); + } + else + { + // General anisotropic scaling, general rotation. + // Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world. + // Scale it to get the required size. + out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse()); + } + + return out; +} + +void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type) { const auto obj_idx = get_selected_obj_idx(); - if (obj_idx < 0) return; + if (obj_idx < 0) + return; - const std::string name = "lambda-" + type_name; + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + assert(obj_idx == selection.get_object_idx()); + // Selected instance index in ModelObject. Only valid if there is only one instance selected in the selection. + int instance_idx = selection.get_instance_idx(); + assert(instance_idx != -1); + if (instance_idx == -1) + return; + + // Selected object + ModelObject &model_object = *(*m_objects)[obj_idx]; + // Bounding box of the selected instance in world coordinate system including the translation, without modifiers. + BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx); + + const wxString name = _(L("Generic")) + "-" + _(type_name); TriangleMesh mesh; auto& bed_shape = wxGetApp().preset_bundle->printers.get_edited_preset().config.option("bed_shape")->values; const auto& sz = BoundingBoxf(bed_shape).size(); const auto side = 0.1 * std::max(sz(0), sz(1)); - if (type_name == _("Box")) { + if (type_name == "Box") + // Sitting on the print bed, left front front corner at (0, 0). mesh = make_cube(side, side, side); - // box sets the base coordinate at 0, 0, move to center of plate - mesh.translate(-side * 0.5, -side * 0.5, 0); - } - else if (type_name == _("Cylinder")) - mesh = make_cylinder(0.5*side, side); - else if (type_name == _("Sphere")) - mesh = make_sphere(0.5*side, PI/18); - else if (type_name == _("Slab")) { - const auto& size = (*m_objects)[obj_idx]->bounding_box().size(); - mesh = make_cube(size(0)*1.5, size(1)*1.5, size(2)*0.5); - // box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z - mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, 0); - } + else if (type_name == "Cylinder") + // Centered around 0, sitting on the print bed. + // The cylinder has the same volume as the box above. + mesh = make_cylinder(0.564 * side, side); + else if (type_name == "Sphere") + // Centered around 0, half the sphere below the print bed, half above. + // The sphere has the same volume as the box above. + mesh = make_sphere(0.62 * side, PI / 18); + else if (type_name == "Slab") + // Sitting on the print bed, left front front corner at (0, 0). + mesh = make_cube(instance_bb.size().x()*1.5, instance_bb.size().y()*1.5, instance_bb.size().z()*0.5); mesh.repair(); - auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh); - new_volume->set_type(static_cast(type)); + // Mesh will be centered when loading. + ModelVolume *new_volume = model_object.add_volume(std::move(mesh)); + new_volume->set_type(type); #if !ENABLE_GENERIC_SUBPARTS_PLACEMENT - new_volume->set_offset(Vec3d(0.0, 0.0, (*m_objects)[obj_idx]->origin_translation(2) - mesh.stl.stats.min(2))); + new_volume->set_offset(Vec3d(0.0, 0.0, model_object.origin_translation(2) - mesh.stl.stats.min(2))); #endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT #if !ENABLE_VOLUMES_CENTERING_FIXES new_volume->center_geometry(); #endif // !ENABLE_VOLUMES_CENTERING_FIXES #if ENABLE_GENERIC_SUBPARTS_PLACEMENT - const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); - int instance_idx = selection.get_instance_idx(); if (instance_idx != -1) { + // First (any) GLVolume of the selected instance. They all share the same instance matrix. const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d& inst_m = v->get_instance_transformation().get_matrix(true); - TriangleMesh vol_mesh(mesh); - vol_mesh.transform(inst_m); - Vec3d vol_shift = -vol_mesh.bounding_box().center(); - vol_mesh.translate((float)vol_shift(0), (float)vol_shift(1), (float)vol_shift(2)); - Vec3d world_mesh_bb_size = vol_mesh.bounding_box().size(); - BoundingBoxf3 inst_bb = (*m_objects)[obj_idx]->instance_bounding_box(instance_idx); - Vec3d world_target = Vec3d(inst_bb.max(0), inst_bb.min(1), inst_bb.min(2)) + 0.5 * world_mesh_bb_size; - new_volume->set_offset(inst_m.inverse() * (world_target - v->get_instance_offset())); + // Transform the new modifier to be aligned with the print bed. + const BoundingBoxf3 mesh_bb = new_volume->mesh.bounding_box(); + new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); + // Set the modifier position. + auto offset = (type_name == "Slab") ? + // Slab: Lift to print bed + Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) : + // Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed. + Vec3d(instance_bb.max(0), instance_bb.min(1), instance_bb.min(2)) + 0.5 * mesh_bb.size() - v->get_instance_offset(); + new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset); } #endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT - new_volume->name = name; + new_volume->name = into_u8(name); // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); @@ -1228,7 +1319,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int parts_changed(obj_idx); const auto object_item = m_objects_model->GetTopParent(GetSelection()); - select_item(m_objects_model->AddVolumeChild(object_item, from_u8(name), type)); + select_item(m_objects_model->AddVolumeChild(object_item, name, type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -1360,7 +1451,7 @@ void ObjectList::split() for (auto id = 0; id < model_object->volumes.size(); id++) { const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name), model_object->volumes[id]->is_modifier() ? - ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, + ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? model_object->volumes[id]->config.option("extruder")->value : 0, false); @@ -1962,15 +2053,15 @@ void ObjectList::change_part_type() if (!volume) return; - const auto type = volume->type(); - if (type == ModelVolume::MODEL_PART) + const ModelVolumeType type = volume->type(); + if (type == ModelVolumeType::MODEL_PART) { const int obj_idx = get_selected_obj_idx(); if (obj_idx < 0) return; int model_part_cnt = 0; for (auto vol : (*m_objects)[obj_idx]->volumes) { - if (vol->type() == ModelVolume::MODEL_PART) + if (vol->type() == ModelVolumeType::MODEL_PART) ++model_part_cnt; } @@ -1982,13 +2073,13 @@ void ObjectList::change_part_type() const wxString names[] = { "Part", "Modifier", "Support Enforcer", "Support Blocker" }; - auto new_type = wxGetSingleChoiceIndex("Type: ", _(L("Select type of part")), wxArrayString(4, names), type); + auto new_type = ModelVolumeType(wxGetSingleChoiceIndex("Type: ", _(L("Select type of part")), wxArrayString(4, names), int(type))); - if (new_type == type || new_type < 0) + if (new_type == type || new_type == ModelVolumeType::INVALID) return; const auto item = GetSelection(); - volume->set_type(static_cast(new_type)); + volume->set_type(new_type); m_objects_model->SetVolumeType(item, new_type); m_parts_changed = true; @@ -1998,11 +2089,11 @@ void ObjectList::change_part_type() //(we show additional settings for Part and Modifier and hide it for Support Blocker/Enforcer) const auto settings_item = m_objects_model->GetSettingsItem(item); if (settings_item && - (new_type == ModelVolume::SUPPORT_ENFORCER || new_type == ModelVolume::SUPPORT_BLOCKER)) { + (new_type == ModelVolumeType::SUPPORT_ENFORCER || new_type == ModelVolumeType::SUPPORT_BLOCKER)) { m_objects_model->Delete(settings_item); } else if (!settings_item && - (new_type == ModelVolume::MODEL_PART || new_type == ModelVolume::PARAMETER_MODIFIER)) { + (new_type == ModelVolumeType::MODEL_PART || new_type == ModelVolumeType::PARAMETER_MODIFIER)) { select_item(m_objects_model->AddSettingsChild(item)); } } diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index e572bec82..138bacac4 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -21,6 +21,7 @@ class ConfigOptionsGroup; class DynamicPrintConfig; class ModelObject; class ModelVolume; +enum class ModelVolumeType : int; // FIXME: broken build on mac os because of this is missing: typedef std::vector t_config_option_keys; @@ -173,7 +174,7 @@ public: void get_freq_settings_choice(const wxString& bundle_name); void update_settings_item(); - void append_menu_item_add_generic(wxMenuItem* menu, const int type); + void append_menu_item_add_generic(wxMenuItem* menu, const ModelVolumeType type); void append_menu_items_add_volume(wxMenu* menu); wxMenuItem* append_menu_item_split(wxMenu* menu); wxMenuItem* append_menu_item_settings(wxMenu* menu); @@ -190,9 +191,9 @@ public: void update_opt_keys(t_config_option_keys& t_optopt_keys); - void load_subobject(int type); - void load_part(ModelObject* model_object, wxArrayString& part_names, int type); - void load_generic_subobject(const std::string& type_name, const int type); + void load_subobject(ModelVolumeType type); + void load_part(ModelObject* model_object, wxArrayString& part_names, ModelVolumeType type); + void load_generic_subobject(const std::string& type_name, const ModelVolumeType type); void del_object(const int obj_idx); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index a00e4676b..ab83df05d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -22,7 +22,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : #endif // __APPLE__ { m_og->set_name(_(L("Object Manipulation"))); - m_og->label_width = 125; + m_og->label_width = 12 * wxGetApp().em_unit();//125; m_og->set_grid_vgap(5); m_og->m_on_change = std::bind(&ObjectManipulation::on_change, this, std::placeholders::_1, std::placeholders::_2); @@ -44,15 +44,17 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : def.label = L("Name"); def.gui_type = "legend"; def.tooltip = L("Object name"); - def.width = 200; + def.width = 21 * wxGetApp().em_unit(); def.default_value = new ConfigOptionString{ " " }; m_og->append_single_option_line(Option(def, "object_name")); + const int field_width = 5 * wxGetApp().em_unit()/*50*/; + // Legend for object modification auto line = Line{ "", "" }; def.label = ""; def.type = coString; - def.width = 50; + def.width = field_width/*50*/; std::vector axes{ "x", "y", "z" }; for (const auto axis : axes) { @@ -64,13 +66,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_og->append_line(line); - auto add_og_to_object_settings = [this](const std::string& option_name, const std::string& sidetext) + auto add_og_to_object_settings = [this, field_width](const std::string& option_name, const std::string& sidetext) { Line line = { _(option_name), "" }; ConfigOptionDef def; def.type = coFloat; def.default_value = new ConfigOptionFloat(0.0); - def.width = 50; + def.width = field_width/*50*/; // Add "uniform scaling" button in front of "Scale" option if (option_name == "Scale") { @@ -88,8 +90,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment else if (option_name == "Size") { line.near_label_widget = [this](wxWindow* parent) { - return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, - wxBitmap(from_u8(var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG).GetSize()); + return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, +// wxBitmap(from_u8(var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG).GetSize()); + create_scaled_bitmap("one_layer_lock_on.png").GetSize()); }; } @@ -358,16 +361,21 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); const GLCanvas3D::Selection& selection = canvas->get_selection(); - Vec3d delta_rotation = rotation - m_cache.rotation; + GLCanvas3D::TransformationType transformation_type(GLCanvas3D::TransformationType::World_Relative_Joint); + if (selection.is_single_full_instance() || selection.requires_local_axes()) + transformation_type.set_independent(); + if (selection.is_single_full_instance()) { + //FIXME GLCanvas3D::Selection::rotate() does not process absoulte rotations correctly: It does not recognize the axis index, which was changed. + // transformation_type.set_absolute(); + transformation_type.set_local(); + } Vec3d rad_rotation; for (size_t i = 0; i < 3; ++i) - { - rad_rotation(i) = Geometry::deg2rad(delta_rotation(i)); - } + rad_rotation(i) = Geometry::deg2rad((transformation_type.absolute()) ? rotation(i) : rotation(i) - m_cache.rotation(i)); canvas->get_selection().start_dragging(); - canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes()); + canvas->get_selection().rotate(rad_rotation, transformation_type); canvas->do_rotate(); m_cache.rotation = rotation; diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 477b0530b..3781cbf45 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -75,7 +75,8 @@ void ObjectSettings::update_settings_list() { auto opt_key = (line.get_options())[0].opt_id; //we assume that we have one option per line - auto btn = new wxBitmapButton(parent, wxID_ANY, wxBitmap(from_u8(var("colorchange_delete_on.png")), wxBITMAP_TYPE_PNG), +// auto btn = new wxBitmapButton(parent, wxID_ANY, wxBitmap(from_u8(var("colorchange_delete_on.png")), wxBITMAP_TYPE_PNG), + auto btn = new wxBitmapButton(parent, wxID_ANY, create_scaled_bitmap("colorchange_delete_on.png"), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); #ifdef __WXMSW__ btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); @@ -98,7 +99,7 @@ void ObjectSettings::update_settings_list() std::vector categories; if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))// return; { - auto extruders_cnt = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA ? 1 : + const int extruders_cnt = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA ? 1 : wxGetApp().preset_bundle->printers.get_edited_preset().config.option("nozzle_diameter")->values.size(); for (auto& opt_key : opt_keys) { @@ -119,8 +120,8 @@ void ObjectSettings::update_settings_list() continue; auto optgroup = std::make_shared(m_parent, cat.first, config, false, extra_column); - optgroup->label_width = 150; - optgroup->sidetext_width = 70; + optgroup->label_width = 15 * wxGetApp().em_unit();//150; + optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70; optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) { wxGetApp().obj_list()->part_settings_changed(); }; @@ -130,7 +131,7 @@ void ObjectSettings::update_settings_list() if (opt == "extruder") continue; Option option = optgroup->get_option(opt); - option.opt.width = 70; + option.opt.width = 7 * wxGetApp().em_unit();//70; optgroup->append_single_option_line(option); } optgroup->reload_config(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 0ad6c3562..7ac3f80e2 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -52,7 +52,7 @@ View3D::~View3D() bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) { - if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)) + if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this); @@ -69,9 +69,6 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba m_canvas->set_config(config); m_canvas->enable_gizmos(true); m_canvas->enable_toolbar(true); -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - m_canvas->enable_force_zoom_to_bed(true); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE #if !ENABLE_IMGUI m_gizmo_widget = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); @@ -92,6 +89,12 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba return true; } +void View3D::set_bed(Bed3D* bed) +{ + if (m_canvas != nullptr) + m_canvas->set_bed(bed); +} + void View3D::set_view_toolbar(GLToolbar* toolbar) { if (m_canvas != nullptr) @@ -104,15 +107,10 @@ void View3D::set_as_dirty() m_canvas->set_as_dirty(); } -void View3D::set_bed_shape(const Pointfs& shape) +void View3D::bed_shape_changed() { if (m_canvas != nullptr) - { - m_canvas->set_bed_shape(shape); -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - m_canvas->zoom_to_bed(); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - } + m_canvas->bed_shape_changed(); } void View3D::select_view(const std::string& direction) @@ -229,7 +227,7 @@ bool Preview::init(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlici if ((config == nullptr) || (process == nullptr) || (gcode_preview_data == nullptr)) return false; - if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)) + if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this); @@ -259,7 +257,7 @@ bool Preview::init(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlici m_label_show_features = new wxStaticText(this, wxID_ANY, _(L("Show"))); m_combochecklist_features = new wxComboCtrl(); - m_combochecklist_features->Create(this, wxID_ANY, _(L("Feature types")), wxDefaultPosition, wxSize(200, -1), wxCB_READONLY); + m_combochecklist_features->Create(this, wxID_ANY, _(L("Feature types")), wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), wxCB_READONLY); std::string feature_text = GUI::into_u8(_(L("Feature types"))); std::string feature_items = GUI::into_u8( _(L("Perimeter")) + "|" + @@ -345,6 +343,12 @@ Preview::~Preview() } } +void Preview::set_bed(Bed3D* bed) +{ + if (m_canvas != nullptr) + m_canvas->set_bed(bed); +} + void Preview::set_view_toolbar(GLToolbar* toolbar) { if (m_canvas != nullptr) @@ -376,9 +380,10 @@ void Preview::set_enabled(bool enabled) m_enabled = enabled; } -void Preview::set_bed_shape(const Pointfs& shape) +void Preview::bed_shape_changed() { - m_canvas->set_bed_shape(shape); + if (m_canvas != nullptr) + m_canvas->bed_shape_changed(); } void Preview::select_view(const std::string& direction) @@ -413,11 +418,14 @@ void Preview::load_print() load_print_as_sla(); } -void Preview::reload_print(bool force) +void Preview::reload_print(bool force, bool keep_volumes) { - m_canvas->reset_volumes(); - m_canvas->reset_legend_texture(); - m_loaded = false; + if (!keep_volumes) + { + m_canvas->reset_volumes(); + m_canvas->reset_legend_texture(); + m_loaded = false; + } if (!IsShown() && !force) return; @@ -558,8 +566,12 @@ void Preview::create_double_slider() auto& config = wxGetApp().preset_bundle->project_config; ((config.option("colorprint_heights"))->values) = (m_slider->GetTicksValues()); m_schedule_background_process(); - bool color_print = !config.option("colorprint_heights")->values.empty(); - int type = m_choice_view_type->FindString(color_print ? _(L("Color Print")) : _(L("Feature type")) ); + + const wxString& choise = !config.option("colorprint_heights")->values.empty() ? _(L("Color Print")) : + config.option("wiping_volumes_matrix")->values.size() > 1 ? + _(L("Tool")) : _(L("Feature type")); + + int type = m_choice_view_type->FindString(choise); if (m_choice_view_type->GetSelection() != type) { m_choice_view_type->SetSelection(type); if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) @@ -632,12 +644,13 @@ void Preview::update_double_slider(const std::vector& layers_z, bool for const auto& config = wxGetApp().preset_bundle->project_config; const std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + m_slider->SetTicksValues(ticks_from_config); bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); if (color_print_enable) { - const auto& config = wxGetApp().preset_bundle->full_config(); - if (config.opt("nozzle_diameter")->values.size() > 1) + const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; + if (cfg.opt("nozzle_diameter")->values.size() > 1) color_print_enable = false; } m_slider->EnableTickManipulation(color_print_enable); diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 49dbed44d..d3cb4e5bf 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -27,6 +27,7 @@ namespace GUI { class GLCanvas3D; class GLToolbar; +class Bed3D; class View3D : public wxPanel { @@ -48,10 +49,11 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } GLCanvas3D* get_canvas3d() { return m_canvas; } + void set_bed(Bed3D* bed); void set_view_toolbar(GLToolbar* toolbar); void set_as_dirty(); - void set_bed_shape(const Pointfs& shape); + void bed_shape_changed(); void select_view(const std::string& direction); void select_all(); @@ -114,19 +116,20 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } GLCanvas3D* get_canvas3d() { return m_canvas; } + void set_bed(Bed3D* bed); void set_view_toolbar(GLToolbar* toolbar); void set_number_extruders(unsigned int number_extruders); void set_canvas_as_dirty(); void set_enabled(bool enabled); - void set_bed_shape(const Pointfs& shape); + void bed_shape_changed(); void select_view(const std::string& direction); void set_viewport_from_scene(GLCanvas3D* canvas); void set_viewport_into_scene(GLCanvas3D* canvas); void set_drop_target(wxDropTarget* target); void load_print(); - void reload_print(bool force = false); + void reload_print(bool force = false, bool keep_volumes = false); void refresh_print(); private: diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index db0264459..56d6eaeb5 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -26,6 +26,28 @@ wxTopLevelWindow* find_toplevel_parent(wxWindow *window) return nullptr; } +void on_window_geometry(wxTopLevelWindow *tlw, std::function callback) +{ +#ifdef _WIN32 + // On windows, the wxEVT_SHOW is not received if the window is created maximized + // cf. https://groups.google.com/forum/#!topic/wx-users/c7ntMt6piRI + // OTOH the geometry is available very soon, so we can call the callback right away + callback(); +#elif defined __linux__ + tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) { + // On Linux, the geometry is only available after wxEVT_SHOW + CallAfter + // cf. https://groups.google.com/forum/?pli=1#!topic/wx-users/fERSXdpVwAI + tlw->CallAfter([=]() { callback(); }); + evt.Skip(); + }); +#elif defined __APPLE__ + tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) { + callback(); + evt.Skip(); + }); +#endif +} + CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY) diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 8ca4d9383..d84dd40f9 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -24,6 +25,8 @@ namespace GUI { wxTopLevelWindow* find_toplevel_parent(wxWindow *window); +void on_window_geometry(wxTopLevelWindow *tlw, std::function callback); + class EventGuard { diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index e36a68eda..7f95b6c28 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -25,10 +26,12 @@ namespace GUI { ImGuiWrapper::ImGuiWrapper() - : m_font_texture(0) + : m_glyph_ranges(nullptr) + , m_font_texture(0) , m_style_scaling(1.0) , m_mouse_buttons(0) , m_disabled(false) + , m_new_frame_open(false) { } @@ -43,12 +46,43 @@ bool ImGuiWrapper::init() ImGui::CreateContext(); init_default_font(m_style_scaling); + init_input(); + init_style(); ImGui::GetIO().IniFilename = nullptr; return true; } +void ImGuiWrapper::set_language(const std::string &language) +{ + const ImWchar *ranges = nullptr; + size_t idx = language.find('_'); + std::string lang = (idx == std::string::npos) ? language : language.substr(0, idx); + static const ImWchar ranges_latin2[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0100, 0x017F, // Latin Extended-A + 0, + }; + if (lang == "cs" || lang == "pl") { + ranges = ranges_latin2; + } else if (lang == "ru" || lang == "uk") { + ranges = ImGui::GetIO().Fonts->GetGlyphRangesCyrillic(); + } else if (lang == "jp") { + ranges = ImGui::GetIO().Fonts->GetGlyphRangesJapanese(); + } else if (lang == "kr") { + ranges = ImGui::GetIO().Fonts->GetGlyphRangesKorean(); + } else if (lang == "zh") { + ranges = ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon(); + } + + if (ranges != m_glyph_ranges) { + m_glyph_ranges = ranges; + init_default_font(m_style_scaling); + } +} + void ImGuiWrapper::set_display_size(float w, float h) { ImGuiIO& io = ImGui::GetIO(); @@ -67,6 +101,10 @@ void ImGuiWrapper::set_style_scaling(float scaling) bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) { + if (! display_initialized()) { + return false; + } + ImGuiIO& io = ImGui::GetIO(); io.MousePos = ImVec2((float)evt.GetX(), (float)evt.GetY()); io.MouseDown[0] = evt.LeftDown(); @@ -74,23 +112,63 @@ bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) io.MouseDown[2] = evt.MiddleDown(); unsigned buttons = (evt.LeftDown() ? 1 : 0) | (evt.RightDown() ? 2 : 0) | (evt.MiddleDown() ? 4 : 0); - bool res = buttons != m_mouse_buttons; m_mouse_buttons = buttons; - return res; + + new_frame(); + return want_mouse(); +} + +bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) +{ + if (! display_initialized()) { + return false; + } + + ImGuiIO& io = ImGui::GetIO(); + + if (evt.GetEventType() == wxEVT_CHAR) { + // Char event + const auto key = evt.GetUnicodeKey(); + if (key != 0) { + io.AddInputCharacter(key); + } + + new_frame(); + return want_keyboard() || want_text_input(); + } else { + // Key up/down event + int key = evt.GetKeyCode(); + wxCHECK_MSG(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown), false, "Received invalid key code"); + + io.KeysDown[key] = evt.GetEventType() == wxEVT_KEY_DOWN; + io.KeyShift = evt.ShiftDown(); + io.KeyCtrl = evt.ControlDown(); + io.KeyAlt = evt.AltDown(); + io.KeySuper = evt.MetaDown(); + + new_frame(); + return want_keyboard() || want_text_input(); + } } void ImGuiWrapper::new_frame() { + if (m_new_frame_open) { + return; + } + if (m_font_texture == 0) create_device_objects(); ImGui::NewFrame(); + m_new_frame_open = true; } void ImGuiWrapper::render() { ImGui::Render(); render_draw_data(ImGui::GetDrawData()); + m_new_frame_open = false; } void ImGuiWrapper::set_next_window_pos(float x, float y, int flag) @@ -125,6 +203,12 @@ bool ImGuiWrapper::button(const wxString &label) return ImGui::Button(label_utf8.c_str()); } +bool ImGuiWrapper::radio_button(const wxString &label, bool active) +{ + auto label_utf8 = into_u8(label); + return ImGui::RadioButton(label_utf8.c_str(), active); +} + bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format) { return ImGui::InputDouble(label.c_str(), const_cast(&value), 0.0f, 0.0f, format.c_str()); @@ -161,6 +245,28 @@ void ImGuiWrapper::text(const wxString &label) ImGui::Text(label_utf8.c_str(), NULL); } + +bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, wxString& selection) +{ + std::string selection_u8 = into_u8(selection); + + // this is to force the label to the left of the widget: + text(label); + ImGui::SameLine(); + + if (ImGui::BeginCombo("", selection_u8.c_str())) { + for (const wxString& option : options) { + std::string option_u8 = into_u8(option); + bool is_selected = (selection_u8.empty()) ? false : (option_u8 == selection_u8); + if (ImGui::Selectable(option_u8.c_str(), is_selected)) + selection = option_u8; + } + ImGui::EndCombo(); + return true; + } + return false; +} + void ImGuiWrapper::disabled_begin(bool disabled) { wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); @@ -210,7 +316,7 @@ void ImGuiWrapper::init_default_font(float scaling) ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); - ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size * scaling); + ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size * scaling, nullptr, m_glyph_ranges); if (font == nullptr) { font = io.Fonts->AddFontDefault(); if (font == nullptr) { @@ -249,6 +355,82 @@ void ImGuiWrapper::create_fonts_texture() glBindTexture(GL_TEXTURE_2D, last_texture); } +void ImGuiWrapper::init_input() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. + io.KeyMap[ImGuiKey_Tab] = WXK_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = WXK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = WXK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = WXK_UP; + io.KeyMap[ImGuiKey_DownArrow] = WXK_DOWN; + io.KeyMap[ImGuiKey_PageUp] = WXK_PAGEUP; + io.KeyMap[ImGuiKey_PageDown] = WXK_PAGEDOWN; + io.KeyMap[ImGuiKey_Home] = WXK_HOME; + io.KeyMap[ImGuiKey_End] = WXK_END; + io.KeyMap[ImGuiKey_Insert] = WXK_INSERT; + io.KeyMap[ImGuiKey_Delete] = WXK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = WXK_BACK; + io.KeyMap[ImGuiKey_Space] = WXK_SPACE; + io.KeyMap[ImGuiKey_Enter] = WXK_RETURN; + io.KeyMap[ImGuiKey_Escape] = WXK_ESCAPE; + io.KeyMap[ImGuiKey_A] = 'A'; + io.KeyMap[ImGuiKey_C] = 'C'; + io.KeyMap[ImGuiKey_V] = 'V'; + io.KeyMap[ImGuiKey_X] = 'X'; + io.KeyMap[ImGuiKey_Y] = 'Y'; + io.KeyMap[ImGuiKey_Z] = 'Z'; + + // Don't let imgui special-case Mac, wxWidgets already do that + io.ConfigMacOSXBehaviors = false; + + // Setup clipboard interaction callbacks + io.SetClipboardTextFn = clipboard_set; + io.GetClipboardTextFn = clipboard_get; + io.ClipboardUserData = this; +} + +void ImGuiWrapper::init_style() +{ + ImGuiStyle &style = ImGui::GetStyle(); + + auto set_color = [&](ImGuiCol_ col, unsigned hex_color) { + style.Colors[col] = ImVec4( + ((hex_color >> 24) & 0xff) / 255.0f, + ((hex_color >> 16) & 0xff) / 255.0f, + ((hex_color >> 8) & 0xff) / 255.0f, + (hex_color & 0xff) / 255.0f); + }; + + static const unsigned COL_GREY_DARK = 0x444444ff; + static const unsigned COL_GREY_LIGHT = 0x666666ff; + static const unsigned COL_ORANGE_DARK = 0xc16737ff; + static const unsigned COL_ORANGE_LIGHT = 0xff7d38ff; + + // Generics + set_color(ImGuiCol_TitleBgActive, COL_ORANGE_DARK); + set_color(ImGuiCol_FrameBg, COL_GREY_DARK); + set_color(ImGuiCol_FrameBgHovered, COL_GREY_LIGHT); + set_color(ImGuiCol_FrameBgActive, COL_GREY_LIGHT); + + // Text selection + set_color(ImGuiCol_TextSelectedBg, COL_ORANGE_DARK); + + // Buttons + set_color(ImGuiCol_Button, COL_ORANGE_DARK); + set_color(ImGuiCol_ButtonHovered, COL_ORANGE_LIGHT); + set_color(ImGuiCol_ButtonActive, COL_ORANGE_LIGHT); + + // Checkbox + set_color(ImGuiCol_CheckMark, COL_ORANGE_LIGHT); + + // ComboBox items + set_color(ImGuiCol_Header, COL_ORANGE_DARK); + set_color(ImGuiCol_HeaderHovered, COL_ORANGE_LIGHT); + set_color(ImGuiCol_HeaderActive, COL_ORANGE_LIGHT); +} + void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) @@ -347,6 +529,12 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } +bool ImGuiWrapper::display_initialized() const +{ + const ImGuiIO& io = ImGui::GetIO(); + return io.DisplaySize.x >= 0.0f && io.DisplaySize.y >= 0.0f; +} + void ImGuiWrapper::destroy_device_objects() { destroy_fonts_texture(); @@ -362,6 +550,37 @@ void ImGuiWrapper::destroy_fonts_texture() } } +const char* ImGuiWrapper::clipboard_get(void* user_data) +{ + ImGuiWrapper *self = reinterpret_cast(user_data); + + const char* res = ""; + + if (wxTheClipboard->Open()) { + if (wxTheClipboard->IsSupported(wxDF_TEXT)) { + wxTextDataObject data; + wxTheClipboard->GetData(data); + + if (data.GetTextLength() > 0) { + self->m_clipboard_text = into_u8(data.GetText()); + res = self->m_clipboard_text.c_str(); + } + } + + wxTheClipboard->Close(); + } + + return res; +} + +void ImGuiWrapper::clipboard_set(void* /* user_data */, const char* text) +{ + if (wxTheClipboard->Open()) { + wxTheClipboard->SetData(new wxTextDataObject(wxString::FromUTF8(text))); // object owned by the clipboard + wxTheClipboard->Close(); + } +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 47a1fb937..2cadc773c 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -10,6 +10,7 @@ class wxString; class wxMouseEvent; +class wxKeyEvent; namespace Slic3r { @@ -20,10 +21,13 @@ class ImGuiWrapper typedef std::map FontsMap; FontsMap m_fonts; + const ImWchar *m_glyph_ranges; unsigned m_font_texture; float m_style_scaling; unsigned m_mouse_buttons; bool m_disabled; + bool m_new_frame_open; + std::string m_clipboard_text; public: ImGuiWrapper(); @@ -32,9 +36,11 @@ public: bool init(); void read_glsl_version(); + void set_language(const std::string &language); void set_display_size(float w, float h); void set_style_scaling(float scaling); bool update_mouse_data(wxMouseEvent &evt); + bool update_key_data(wxKeyEvent &evt); void new_frame(); void render(); @@ -47,10 +53,12 @@ public: void end(); bool button(const wxString &label); + bool radio_button(const wxString &label, bool active); bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f"); bool checkbox(const wxString &label, bool &value); void text(const wxString &label); + bool combo(const wxString& label, const std::vector& options, wxString& current_selection); void disabled_begin(bool disabled); void disabled_end(); @@ -59,13 +67,20 @@ public: bool want_keyboard() const; bool want_text_input() const; bool want_any_input() const; + private: void init_default_font(float scaling); void create_device_objects(); void create_fonts_texture(); + void init_input(); + void init_style(); void render_draw_data(ImDrawData *draw_data); + bool display_initialized() const; void destroy_device_objects(); void destroy_fonts_texture(); + + static const char* clipboard_get(void* user_data); + static void clipboard_set(void* user_data, const char* text); }; diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index d893d6f76..66e9deec8 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -4,6 +4,7 @@ #include "GUI.hpp" #include #include "GUI_App.hpp" +#include "wxExtensions.hpp" namespace Slic3r { namespace GUI { @@ -16,7 +17,8 @@ KBShortcutsDialog::KBShortcutsDialog() auto main_sizer = new wxBoxSizer(wxVERTICAL); // logo - wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_32px.png")), wxBITMAP_TYPE_PNG); +// wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_32px.png")), wxBITMAP_TYPE_PNG); + const wxBitmap logo_bmp = create_scaled_bitmap("Slic3r_32px.png"); // fonts wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); @@ -54,7 +56,7 @@ KBShortcutsDialog::KBShortcutsDialog() hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 15); // head - wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(200,-1)); + wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(20 * wxGetApp().em_unit(), -1)); head->SetFont(head_font); hsizer->Add(head, 0, wxALIGN_CENTER_VERTICAL); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index ed6a51e61..8d7fa13b1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -53,6 +53,11 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL SLIC3R_VERSION + _(L(" - Remember to check for updates at http://github.com/supermerill/slic3r/releases"))); + + // initialize default width_unit according to the width of the one symbol ("x") of the current system font + const wxSize size = GetTextExtent("m"); + wxGetApp().set_em_unit(size.x-1); + // initialize tabpanel and menubar init_tabpanel(); init_menubar(); @@ -105,6 +110,12 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL event.Skip(); }); + Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) { + if (m_plater != nullptr && event.GetActive()) + m_plater->on_activate(); + event.Skip(); + }); + wxGetApp().persist_window_geometry(this); update_ui_from_settings(); // FIXME (?) @@ -136,11 +147,11 @@ void MainFrame::init_tabpanel() wxGetApp().obj_list()->create_popup_menus(); // The following event is emited by Tab implementation on config value change. - Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this); + Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this); // #ys_FIXME_to_delete // The following event is emited by Tab on preset selection, // or when the preset's "modified" status changes. - Bind(EVT_TAB_PRESETS_CHANGED, &MainFrame::on_presets_changed, this); + Bind(EVT_TAB_PRESETS_CHANGED, &MainFrame::on_presets_changed, this); // #ys_FIXME_to_delete create_preset_tabs(); @@ -550,9 +561,6 @@ void MainFrame::quick_slice(const int qs) } else if (qs & qsSaveAs) { // The following line may die if the output_filename_format template substitution fails. -// output_file = sprint->output_filepath; -// if (export_svg) -// output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .svg /; auto dlg = new wxFileDialog(this, _(L("Save ")) + (qs & qsExportSVG ? _(L("SVG")) : _(L("G-code"))) + _(L(" file as:")), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file), qs & qsExportSVG ? file_wildcards(FT_SVG) : file_wildcards(FT_GCODE), @@ -568,11 +576,9 @@ void MainFrame::quick_slice(const int qs) wxGetApp().app_config->update_last_output_dir(get_dir_name(output_file)); } else if (qs & qsExportPNG) { -// output_file = sprint->output_filepath; -// output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .zip / ; auto dlg = new wxFileDialog(this, _(L("Save zip file as:")), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), - get_base_name(output_file), "*.zip", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + get_base_name(output_file), "*.sl1", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (dlg->ShowModal() != wxID_OK) { dlg->Destroy(); return; @@ -826,6 +832,7 @@ void MainFrame::select_view(const std::string& direction) m_plater->select_view(direction); } +// #ys_FIXME_to_delete void MainFrame::on_presets_changed(SimpleEvent &event) { auto *tab = dynamic_cast(event.GetEventObject()); @@ -850,6 +857,7 @@ void MainFrame::on_presets_changed(SimpleEvent &event) } } +// #ys_FIXME_to_delete void MainFrame::on_value_changed(wxCommandEvent& event) { auto *tab = dynamic_cast(event.GetEventObject()); @@ -865,12 +873,12 @@ void MainFrame::on_value_changed(wxCommandEvent& event) m_plater->on_extruders_change(value); } } - // Don't save while loading for the first time. - if (m_loaded) { - AppConfig &cfg = *wxGetApp().app_config; - if (cfg.get("autosave") == "1") - cfg.save(); - } +} + +void MainFrame::on_config_changed(DynamicPrintConfig* config) const +{ + if (m_plater) + m_plater->on_config_change(*config); // propagate config change events to the plater } // Called after the Preferences dialog is closed and the program settings are saved. diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 31ae5d1c7..b44c73f91 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -96,6 +96,8 @@ public: void load_config(const DynamicPrintConfig& config); void select_tab(size_t tab) const; void select_view(const std::string& direction); + // Propagate changed configuration from the Tab to the Platter and save changes to the AppConfig + void on_config_changed(DynamicPrintConfig* cfg) const ; PrintHostQueueDialog* printhost_queue_dlg() { return m_printhost_queue_dlg; } diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index d6b8b438e..176d19fb4 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -7,19 +7,25 @@ #include #include #include +#include + +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "GUI.hpp" #include "I18N.hpp" #include "ConfigWizard.hpp" +#include "wxExtensions.hpp" +#include "GUI_App.hpp" namespace Slic3r { namespace GUI { MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id) : - MsgDialog(parent, title, headline, wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG), button_id) +// MsgDialog(parent, title, headline, wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG), button_id) + MsgDialog(parent, title, headline, create_scaled_bitmap("Slic3r_192px.png"), button_id) {} MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : @@ -35,7 +41,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he auto *headtext = new wxStaticText(this, wxID_ANY, headline); headtext->SetFont(boldfont); - headtext->Wrap(CONTENT_WIDTH); + headtext->Wrap(CONTENT_WIDTH*wxGetApp().em_unit()); rightsizer->Add(headtext); rightsizer->AddSpacer(VERT_SPACING); @@ -47,7 +53,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he btn_sizer->Add(button); } - rightsizer->Add(btn_sizer, 0, wxALIGN_CENTRE_HORIZONTAL); + rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT); auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(bitmap)); @@ -64,38 +70,36 @@ MsgDialog::~MsgDialog() {} ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) : MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")), - wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG), +// wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG), + create_scaled_bitmap("Slic3r_192px_grayscale.png"), wxID_NONE) , msg(msg) { - auto *panel = new wxScrolledWindow(this); - auto *p_sizer = new wxBoxSizer(wxVERTICAL); - panel->SetSizer(p_sizer); - - auto *text = new wxStaticText(panel, wxID_ANY, msg); - text->Wrap(CONTENT_WIDTH); - p_sizer->Add(text, 1, wxEXPAND); - - panel->SetMinSize(wxSize(CONTENT_WIDTH, 0)); - panel->SetScrollRate(0, 5); - - content_sizer->Add(panel, 1, wxEXPAND); - - auto *btn_copy = new wxButton(this, wxID_ANY, _(L("Copy to clipboard"))); - btn_copy->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { - if (wxTheClipboard->Open()) { - wxTheClipboard->SetData(new wxTextDataObject(this->msg)); // Note: the clipboard takes ownership of the pointer - wxTheClipboard->Close(); - } - }); + // Text shown as HTML, so that mouse selection and Ctrl-V to copy will work. + wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); + { + html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1)); + wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK); // wxSYS_COLOUR_WINDOW + auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); + auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); + const int font_size = font.GetPointSize()-1; + int size[] = {font_size, font_size, font_size, font_size, font_size, font_size, font_size}; + html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); + html->SetBorders(2); + std::string msg_escaped = xml_escape(msg.ToUTF8().data()); + boost::replace_all(msg_escaped, "\r\n", "
"); + boost::replace_all(msg_escaped, "\n", "
"); + html->SetPage("" + wxString::FromUTF8(msg_escaped.data()) + ""); + content_sizer->Add(html, 1, wxEXPAND); + } auto *btn_ok = new wxButton(this, wxID_OK); btn_ok->SetFocus(); + btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING); - btn_sizer->Add(btn_copy, 0, wxRIGHT, HORIZ_SPACING); - btn_sizer->Add(btn_ok); - - SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT)); + SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit())); Fit(); } diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index 6064d2a9f..09bb89e4f 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -32,8 +32,8 @@ struct MsgDialog : wxDialog protected: enum { - CONTENT_WIDTH = 500, - CONTENT_MAX_HEIGHT = 600, + CONTENT_WIDTH = 50, + CONTENT_MAX_HEIGHT = 60, BORDER = 30, VERT_SPACING = 15, HORIZ_SPACING = 5, diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 2bd2206e5..b5c118c3b 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -113,7 +113,6 @@ void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& fiel } void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = nullptr*/) { -//! if (line.sizer != nullptr || (line.widget != nullptr && line.full_width > 0)) { if ( (line.sizer != nullptr || line.widget != nullptr) && line.full_width) { if (line.sizer != nullptr) { sizer->Add(line.sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); @@ -135,6 +134,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n // if we have a single option with no label, no sidetext just add it directly to sizer if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width && + option_set.front().opt.label.empty() && option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { wxSizer* tmp_sizer; @@ -184,7 +184,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n label->SetFont(label_font); label->Wrap(label_width); // avoid a Linux/GTK bug if (!line.near_label_widget) - grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); + grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5); else { // If we're here, we have some widget near the label // so we need a horizontal sizer to arrange these things @@ -213,6 +213,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); // If we have a single option with no sidetext just add it directly to the grid sizer if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && + option_set.front().opt.label.empty() && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { const auto& option = option_set.front(); const auto& field = build_field(option, label); @@ -245,6 +246,16 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n const Option& opt_ref = opt; auto& field = build_field(opt_ref, label); add_undo_buttuns_to_sizer(sizer_tmp, field); + if (option_set.size() == 1 && option_set.front().opt.full_width) + { + const auto v_sizer = new wxBoxSizer(wxVERTICAL); + sizer_tmp->Add(v_sizer, 1, wxEXPAND); + is_sizer_field(field) ? + v_sizer->Add(field->getSizer(), 0, wxEXPAND) : + v_sizer->Add(field->getWindow(), 0, wxEXPAND); + return; + } + is_sizer_field(field) ? sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) : sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0); @@ -269,7 +280,17 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n } } // add extra sizers if any - for (auto extra_widget : line.get_extra_widgets()) { + for (auto extra_widget : line.get_extra_widgets()) + { + if (line.get_extra_widgets().size() == 1 && !staticbox) + { + // extra widget for non-staticbox option group (like for the frequently used parameters on the sidebar) should be wxALIGN_RIGHT + const auto v_sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add(v_sizer, 1, wxEXPAND); + v_sizer->Add(extra_widget(parent()), 0, wxALIGN_RIGHT); + return; + } + sizer->Add(extra_widget(parent())/*!.target()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification } } @@ -538,8 +559,10 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config ret = config.opt_int(opt_key, idx); break; case coEnum:{ - if (opt_key.compare("top_fill_pattern") == 0 || opt_key.compare("bottom_fill_pattern") == 0 || - opt_key.compare("solid_fill_pattern") == 0 || opt_key.compare("fill_pattern") == 0) { + if (opt_key == "top_fill_pattern" || + opt_key == "bottom_fill_pattern" || + opt_key == "solid_fill_pattern" || + opt_key == "fill_pattern" ) { ret = static_cast(config.option>(opt_key)->value); } else if (opt_key.compare("gcode_flavor") == 0 ) { @@ -608,7 +631,7 @@ Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int op void ogStaticText::SetText(const wxString& value, bool wrap/* = true*/) { SetLabel(value); - if (wrap) Wrap(400); + if (wrap) Wrap(40 * wxGetApp().em_unit()); GetParent()->Layout(); } diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 93151f33e..d9ff6a01a 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -82,7 +82,7 @@ class OptionsGroup { public: const bool staticbox {true}; const wxString title {wxString("")}; - size_t label_width {200}; + size_t label_width = 20 * wxGetApp().em_unit();// {200}; wxSizer* sizer {nullptr}; column_t extra_column {nullptr}; t_change m_on_change { nullptr }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 774e61024..037c0218a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -50,6 +49,7 @@ #include "GLCanvas3D.hpp" #include "GLToolbar.hpp" #include "GUI_Preview.hpp" +#include "3DBed.hpp" #include "Tab.hpp" #include "PresetBundle.hpp" #include "BackgroundSlicingProcess.hpp" @@ -99,6 +99,11 @@ public: wxStaticText *info_facets; wxStaticText *info_materials; wxStaticText *info_manifold; + + wxStaticText *label_volume; + wxStaticText *label_materials; + std::vector sla_hidden_items; + bool showing_manifold_warning_icon; void show_sizer(bool show); }; @@ -120,15 +125,16 @@ ObjectInfo::ObjectInfo(wxWindow *parent) : (*info_label)->SetFont(wxGetApp().small_font()); grid_sizer->Add(text, 0); grid_sizer->Add(*info_label, 0); + return text; }; init_info_label(&info_size, _(L("Size"))); - init_info_label(&info_volume, _(L("Volume"))); + label_volume = init_info_label(&info_volume, _(L("Volume"))); init_info_label(&info_facets, _(L("Facets"))); - init_info_label(&info_materials, _(L("Materials"))); + label_materials = init_info_label(&info_materials, _(L("Materials"))); Add(grid_sizer, 0, wxEXPAND); - auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _(L("Manifold"))); + auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _(L("Manifold")) + ":"); info_manifold_text->SetFont(wxGetApp().small_font()); info_manifold = new wxStaticText(parent, wxID_ANY, ""); info_manifold->SetFont(wxGetApp().small_font()); @@ -139,6 +145,8 @@ ObjectInfo::ObjectInfo(wxWindow *parent) : sizer_manifold->Add(manifold_warning_icon, 0, wxLEFT, 2); sizer_manifold->Add(info_manifold, 0, wxLEFT, 2); Add(sizer_manifold, 0, wxEXPAND | wxTOP, 4); + + sla_hidden_items = { label_volume, info_volume, label_materials, info_materials }; } void ObjectInfo::show_sizer(bool show) @@ -153,6 +161,7 @@ enum SlisedInfoIdx siFilament_m, siFilament_mm3, siFilament_g, + siMateril_unit, siCost, siEstimatedTime, siWTNumbetOfToolchanges, @@ -193,6 +202,7 @@ SlicedInfo::SlicedInfo(wxWindow *parent) : init_info_label(_(L("Used Filament (m)"))); init_info_label(_(L("Used Filament (mm³)"))); init_info_label(_(L("Used Filament (g)"))); + init_info_label(_(L("Used Material (unit)"))); init_info_label(_(L("Cost"))); init_info_label(_(L("Estimated printing time"))); init_info_label(_(L("Number of tool changes"))); @@ -213,7 +223,7 @@ void SlicedInfo::SetTextAndShow(SlisedInfoIdx idx, const wxString& text, const w } PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) : - wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200,-1), 0, nullptr, wxCB_READONLY), +wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), 0, nullptr, wxCB_READONLY), preset_type(preset_type), last_selected(wxNOT_FOUND) { @@ -306,7 +316,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : // Frequently changed parameters for FFF_technology m_og->set_config(config); - m_og->label_width = label_width; + m_og->label_width = label_width == 0 ? 1 : label_width; m_og->m_on_change = [config, this](t_config_option_key opt_key, boost::any value) { Tab* tab_print = wxGetApp().get_tab(Preset::TYPE_PRINT); @@ -351,29 +361,35 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : tab_print->update_dirty(); }; - Option option = m_og->get_option("fill_density"); - option.opt.sidetext = ""; - option.opt.full_width = true; - m_og->append_single_option_line(option); + + Line line = Line { "", "" }; ConfigOptionDef def; - - def.label = L("Support"); + def.label = L("Supports"); def.type = coStrings; def.gui_type = "select_open"; def.tooltip = L("Select what kind of support do you need"); def.enum_labels.push_back(L("None")); def.enum_labels.push_back(L("Support on build plate only")); def.enum_labels.push_back(L("Everywhere")); - std::string selection = !config->opt_bool("support_material") ? - "None" : - config->opt_bool("support_material_buildplate_only") ? - "Support on build plate only" : - "Everywhere"; + const std::string selection = !config->opt_bool("support_material") ? + "None" : config->opt_bool("support_material_buildplate_only") ? + "Support on build plate only" : + "Everywhere"; def.default_value = new ConfigOptionStrings{ selection }; - option = Option(def, "support"); + Option option = Option(def, "support"); option.opt.full_width = true; - m_og->append_single_option_line(option); + line.append_option(option); + m_og->append_line(line); + + + line = Line { "", "" }; + + option = m_og->get_option("fill_density"); + option.opt.label = L("Infill"); + option.opt.width = 7 * wxGetApp().em_unit(); + option.opt.sidetext = " "; + line.append_option(option); m_brim_width = config->opt_float("brim_width"); def.label = L("Brim"); @@ -382,11 +398,10 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : def.gui_type = ""; def.default_value = new ConfigOptionBool{ m_brim_width > 0.0 ? true : false }; option = Option(def, "brim"); - m_og->append_single_option_line(option); + option.opt.sidetext = " "; + line.append_option(option); - - Line line = { "", "" }; - line.widget = [config, this](wxWindow* parent) { + auto wiping_dialog_btn = [config, this](wxWindow* parent) { m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_wiping_dialog_button); @@ -403,19 +418,20 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : std::vector extruders = dlg.get_extruders(); (config.option("wiping_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); (config.option("wiping_volumes_extruders"))->values = std::vector(extruders.begin(), extruders.end()); - wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent)); + wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent)); } })); return sizer; }; - m_og->append_line(line); + line.append_widget(wiping_dialog_btn); + m_og->append_line(line); // Frequently changed parameters for SLA_technology m_og_sla = std::make_shared(parent, ""); DynamicPrintConfig* config_sla = &wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; m_og_sla->set_config(config_sla); - m_og_sla->label_width = label_width*2; + m_og_sla->label_width = label_width == 0 ? 1 : label_width; m_og_sla->m_on_change = [config_sla, this](t_config_option_key opt_key, boost::any value) { Tab* tab = wxGetApp().get_tab(Preset::TYPE_SLA_PRINT); @@ -429,12 +445,22 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : tab->update_dirty(); }; - m_og_sla->append_single_option_line("supports_enable"); - m_og_sla->append_single_option_line("pad_enable"); + + line = Line{ "", "" }; + + option = m_og_sla->get_option("supports_enable"); + option.opt.sidetext = " "; + line.append_option(option); + + option = m_og_sla->get_option("pad_enable"); + option.opt.sidetext = " "; + line.append_option(option); + + m_og_sla->append_line(line); m_sizer = new wxBoxSizer(wxVERTICAL); m_sizer->Add(m_og->sizer, 0, wxEXPAND); - m_sizer->Add(m_og_sla->sizer, 0, wxEXPAND | wxTOP, 5); + m_sizer->Add(m_og_sla->sizer, 0, wxEXPAND); } @@ -495,7 +521,7 @@ struct Sidebar::priv void Sidebar::priv::show_preset_comboboxes() { - const bool showSLA = plater->printer_technology() == ptSLA; + const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; wxWindowUpdateLocker noUpdates_scrolled(scrolled->GetParent()); @@ -519,7 +545,7 @@ void Sidebar::priv::show_preset_comboboxes() Sidebar::Sidebar(Plater *parent) : wxPanel(parent), p(new priv(parent)) { - p->scrolled = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(400, -1)); + p->scrolled = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1)); p->scrolled->SetScrollbars(0, 20, 1, 2); // Sizer in the scrolled area @@ -527,26 +553,26 @@ Sidebar::Sidebar(Plater *parent) p->scrolled->SetSizer(scrolled_sizer); // Sizer with buttons for mode changing - p->mode_sizer = new PrusaModeSizer(p->scrolled); + p->mode_sizer = new PrusaModeSizer(p->scrolled, 2 * wxGetApp().em_unit()); // The preset chooser - p->sizer_presets = new wxFlexGridSizer(5, 2, 1, 2); - p->sizer_presets->AddGrowableCol(1, 1); + p->sizer_presets = new wxFlexGridSizer(10, 1, 1, 2); + p->sizer_presets->AddGrowableCol(0, 1); p->sizer_presets->SetFlexibleDirection(wxBOTH); p->sizer_filaments = new wxBoxSizer(wxVERTICAL); auto init_combo = [this](PresetComboBox **combo, wxString label, Preset::Type preset_type, bool filament) { - auto *text = new wxStaticText(p->scrolled, wxID_ANY, label); + auto *text = new wxStaticText(p->scrolled, wxID_ANY, label+" :"); text->SetFont(wxGetApp().small_font()); *combo = new PresetComboBox(p->scrolled, preset_type); auto *sizer_presets = this->p->sizer_presets; auto *sizer_filaments = this->p->sizer_filaments; - sizer_presets->Add(text, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4); + sizer_presets->Add(text, 0, wxALIGN_LEFT | wxEXPAND | wxRIGHT, 4); if (! filament) { - sizer_presets->Add(*combo, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxBOTTOM, 1); + sizer_presets->Add(*combo, 0, wxEXPAND | wxBOTTOM, 1); } else { - sizer_filaments->Add(*combo, 1, wxEXPAND | wxBOTTOM, 1); + sizer_filaments->Add(*combo, 0, wxEXPAND | wxBOTTOM, 1); (*combo)->set_extruder_idx(0); sizer_presets->Add(sizer_filaments, 1, wxEXPAND); } @@ -560,29 +586,32 @@ Sidebar::Sidebar(Plater *parent) init_combo(&p->combo_printer, _(L("Printer")), Preset::TYPE_PRINTER, false); // calculate width of the preset labels - p->sizer_presets->Layout(); - const wxArrayInt& ar = p->sizer_presets->GetColWidths(); - int label_width = ar.IsEmpty() ? 100 : ar.front()-4; +// p->sizer_presets->Layout(); +// const wxArrayInt& ar = p->sizer_presets->GetColWidths(); +// const int label_width = ar.IsEmpty() ? 10*wxGetApp().em_unit() : ar.front()-4; + + const int margin_5 = int(0.5*wxGetApp().em_unit());// 5; + const int margin_10 = int(1.5*wxGetApp().em_unit());// 15; p->sizer_params = new wxBoxSizer(wxVERTICAL); // Frequently changed parameters - p->frequently_changed_parameters = new FreqChangedParams(p->scrolled, label_width); - p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxBOTTOM | wxLEFT, 2); + p->frequently_changed_parameters = new FreqChangedParams(p->scrolled, 0/*label_width*/); + p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, margin_10); // Object List p->object_list = new ObjectList(p->scrolled); - p->sizer_params->Add(p->object_list->get_sizer(), 1, wxEXPAND | wxTOP, 20); + p->sizer_params->Add(p->object_list->get_sizer(), 1, wxEXPAND); // Object Manipulations p->object_manipulation = new ObjectManipulation(p->scrolled); p->object_manipulation->Hide(); - p->sizer_params->Add(p->object_manipulation->get_sizer(), 0, wxEXPAND | wxLEFT | wxTOP, 20); + p->sizer_params->Add(p->object_manipulation->get_sizer(), 0, wxEXPAND | wxTOP, margin_5); // Frequently Object Settings p->object_settings = new ObjectSettings(p->scrolled); p->object_settings->Hide(); - p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxLEFT | wxTOP, 20); + p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5); wxBitmap arrow_up(GUI::from_u8(Slic3r::var("brick_go.png")), wxBITMAP_TYPE_PNG); p->btn_send_gcode = new wxButton(this, wxID_ANY, _(L("Send to printer"))); @@ -595,11 +624,11 @@ Sidebar::Sidebar(Plater *parent) p->sliced_info = new SlicedInfo(p->scrolled); // Sizer in the scrolled area - scrolled_sizer->Add(p->mode_sizer, 0, wxALIGN_RIGHT/*CENTER_HORIZONTAL*/ | wxBOTTOM | wxRIGHT, 5); - scrolled_sizer->Add(p->sizer_presets, 0, wxEXPAND | wxLEFT, 2); - scrolled_sizer->Add(p->sizer_params, 1, wxEXPAND); - scrolled_sizer->Add(p->object_info, 0, wxEXPAND | wxTOP | wxLEFT, 20); - scrolled_sizer->Add(p->sliced_info, 0, wxEXPAND | wxTOP | wxLEFT, 20); + scrolled_sizer->Add(p->mode_sizer, 0, wxALIGN_CENTER_HORIZONTAL/*RIGHT | wxBOTTOM | wxRIGHT, 5*/); + scrolled_sizer->Add(p->sizer_presets, 0, wxEXPAND | wxLEFT, margin_5); + scrolled_sizer->Add(p->sizer_params, 1, wxEXPAND | wxLEFT, margin_5); + scrolled_sizer->Add(p->object_info, 0, wxEXPAND | wxTOP | wxLEFT, margin_5); + scrolled_sizer->Add(p->sliced_info, 0, wxEXPAND | wxTOP | wxLEFT, margin_5); // Buttons underneath the scrolled area p->btn_export_gcode = new wxButton(this, wxID_ANY, _(L("Export G-code")) + dots); @@ -609,13 +638,13 @@ Sidebar::Sidebar(Plater *parent) enable_buttons(false); auto *btns_sizer = new wxBoxSizer(wxVERTICAL); - btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, 5); - btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, 5); - btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, 5); + btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); + btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); + btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); - sizer->Add(p->scrolled, 1, wxEXPAND | wxTOP, 5); - sizer->Add(btns_sizer, 0, wxEXPAND | wxLEFT, 20); + sizer->Add(p->scrolled, 1, wxEXPAND); + sizer->Add(btns_sizer, 0, wxEXPAND | wxLEFT, margin_5); SetSizer(sizer); // Events @@ -653,11 +682,12 @@ void Sidebar::remove_unused_filament_combos(const int current_extruder_count) void Sidebar::update_presets(Preset::Type preset_type) { PresetBundle &preset_bundle = *wxGetApp().preset_bundle; + const auto print_tech = preset_bundle.printers.get_edited_preset().printer_technology(); switch (preset_type) { case Preset::TYPE_FILAMENT: { - const int extruder_cnt = p->plater->printer_technology() != ptFFF ? 1 : + const int extruder_cnt = print_tech != ptFFF ? 1 : dynamic_cast(preset_bundle.printers.get_edited_preset().config.option("nozzle_diameter"))->values.size(); const int filament_cnt = p->combos_filament.size() > extruder_cnt ? extruder_cnt : p->combos_filament.size(); @@ -689,7 +719,7 @@ void Sidebar::update_presets(Preset::Type preset_type) case Preset::TYPE_PRINTER: { // Update the print choosers to only contain the compatible presets, update the dirty flags. - if (p->plater->printer_technology() == ptFFF) + if (print_tech == ptFFF) preset_bundle.prints.update_platter_ui(p->combo_print); else { preset_bundle.sla_prints.update_platter_ui(p->combo_sla_print); @@ -702,7 +732,7 @@ void Sidebar::update_presets(Preset::Type preset_type) p->combo_printer->check_selection(); // Update the filament choosers to only contain the compatible presets, update the color preview, // update the dirty flags. - if (p->plater->printer_technology() == ptFFF) { + if (print_tech == ptFFF) { for (size_t i = 0; i < p->combos_filament.size(); ++ i) preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); } @@ -809,6 +839,11 @@ void Sidebar::show_info_sizer() } p->object_info->show_sizer(true); + + if (p->plater->printer_technology() == ptSLA) { + for (auto item: p->object_info->sla_hidden_items) + item->Show(false); + } } void Sidebar::show_sliced_info_sizer(const bool show) @@ -817,53 +852,83 @@ void Sidebar::show_sliced_info_sizer(const bool show) p->sliced_info->Show(show); if (show) { - const PrintStatistics& ps = p->plater->fff_print().print_statistics(); - const bool is_wipe_tower = ps.total_wipe_tower_filament > 0; + if (p->plater->printer_technology() == ptSLA) + { + const SLAPrintStatistics& ps = p->plater->sla_print().print_statistics(); + wxString new_label = _(L("Used Material (ml)")) + " :"; + const bool is_supports = ps.support_used_material > 0.0; + if (is_supports) + new_label += wxString::Format("\n - %s\n - %s", _(L("object(s)")), _(L("supports and pad"))); - wxString new_label = _(L("Used Filament (m)")); - if (is_wipe_tower) - new_label += wxString::Format(" :\n - %s\n - %s", _(L("objects")), _(L("wipe tower"))); + wxString info_text = is_supports ? + wxString::Format("%.2f \n%.2f \n%.2f", (ps.objects_used_material + ps.support_used_material) / 1000, + ps.objects_used_material / 1000, + ps.support_used_material / 1000) : + wxString::Format("%.2f", (ps.objects_used_material + ps.support_used_material) / 1000); + p->sliced_info->SetTextAndShow(siMateril_unit, info_text, new_label); - wxString info_text = is_wipe_tower ? - wxString::Format("%.2f \n%.2f \n%.2f", ps.total_used_filament / 1000, - (ps.total_used_filament - ps.total_wipe_tower_filament) / 1000, - ps.total_wipe_tower_filament / 1000) : - wxString::Format("%.2f", ps.total_used_filament / 1000); - p->sliced_info->SetTextAndShow(siFilament_m, info_text, new_label); + p->sliced_info->SetTextAndShow(siCost, "N/A"/*wxString::Format("%.2f", ps.total_cost)*/); + p->sliced_info->SetTextAndShow(siEstimatedTime, ps.estimated_print_time, _(L("Estimated printing time")) + " :"); - p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume)); - p->sliced_info->SetTextAndShow(siFilament_g, wxString::Format("%.2f", ps.total_weight)); - - - new_label = _(L("Cost")); - if (is_wipe_tower) - new_label += wxString::Format(" :\n - %s\n - %s", _(L("objects")), _(L("wipe tower"))); - - info_text = is_wipe_tower ? - wxString::Format("%.2f \n%.2f \n%.2f", ps.total_cost, - (ps.total_cost - ps.total_wipe_tower_cost), - ps.total_wipe_tower_cost) : - wxString::Format("%.2f", ps.total_cost); - p->sliced_info->SetTextAndShow(siCost, info_text, new_label); - - if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A") - p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A"); - else { - new_label = _(L("Estimated printing time")) +" :"; - info_text = ""; - if (ps.estimated_normal_print_time != "N/A") { - new_label += wxString::Format("\n - %s", _(L("normal mode"))); - info_text += wxString::Format("\n%s", ps.estimated_normal_print_time); - } - if (ps.estimated_silent_print_time != "N/A") { - new_label += wxString::Format("\n - %s", _(L("silent mode"))); - info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); - } - p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); + // Hide non-SLA sliced info parameters + p->sliced_info->SetTextAndShow(siFilament_m, "N/A"); + p->sliced_info->SetTextAndShow(siFilament_mm3, "N/A"); + p->sliced_info->SetTextAndShow(siFilament_g, "N/A"); + p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, "N/A"); } + else + { + const PrintStatistics& ps = p->plater->fff_print().print_statistics(); + const bool is_wipe_tower = ps.total_wipe_tower_filament > 0; - // if there is a wipe tower, insert number of toolchanges info into the array: - p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, is_wipe_tower ? wxString::Format("%.d", p->plater->fff_print().wipe_tower_data().number_of_toolchanges) : "N/A"); + wxString new_label = _(L("Used Filament (m)")); + if (is_wipe_tower) + new_label += wxString::Format(" :\n - %s\n - %s", _(L("objects")), _(L("wipe tower"))); + + wxString info_text = is_wipe_tower ? + wxString::Format("%.2f \n%.2f \n%.2f", ps.total_used_filament / 1000, + (ps.total_used_filament - ps.total_wipe_tower_filament) / 1000, + ps.total_wipe_tower_filament / 1000) : + wxString::Format("%.2f", ps.total_used_filament / 1000); + p->sliced_info->SetTextAndShow(siFilament_m, info_text, new_label); + + p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume)); + p->sliced_info->SetTextAndShow(siFilament_g, wxString::Format("%.2f", ps.total_weight)); + + + new_label = _(L("Cost")); + if (is_wipe_tower) + new_label += wxString::Format(" :\n - %s\n - %s", _(L("objects")), _(L("wipe tower"))); + + info_text = is_wipe_tower ? + wxString::Format("%.2f \n%.2f \n%.2f", ps.total_cost, + (ps.total_cost - ps.total_wipe_tower_cost), + ps.total_wipe_tower_cost) : + wxString::Format("%.2f", ps.total_cost); + p->sliced_info->SetTextAndShow(siCost, info_text, new_label); + + if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A") + p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A"); + else { + new_label = _(L("Estimated printing time")) +" :"; + info_text = ""; + if (ps.estimated_normal_print_time != "N/A") { + new_label += wxString::Format("\n - %s", _(L("normal mode"))); + info_text += wxString::Format("\n%s", ps.estimated_normal_print_time); + } + if (ps.estimated_silent_print_time != "N/A") { + new_label += wxString::Format("\n - %s", _(L("silent mode"))); + info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); + } + p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); + } + + // if there is a wipe tower, insert number of toolchanges info into the array: + p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, is_wipe_tower ? wxString::Format("%.d", p->plater->fff_print().wipe_tower_data().number_of_toolchanges) : "N/A"); + + // Hide non-FFF sliced info parameters + p->sliced_info->SetTextAndShow(siMateril_unit, "N/A"); + } } Layout(); @@ -953,6 +1018,7 @@ struct Plater::priv wxPanel* current_panel; std::vector panels; Sidebar *sidebar; + Bed3D bed; View3D* view3D; GLToolbar view_toolbar; Preview *preview; @@ -963,6 +1029,7 @@ struct Plater::priv std::atomic arranging; std::atomic rotoptimizing; bool delayed_scene_refresh; + std::string delayed_error_message; wxTimer background_process_timer; @@ -1056,6 +1123,12 @@ struct Plater::priv void update_object_menu(); + // Set the bed shape to a single closed 2D polygon(array of two element arrays), + // triangulate the bed and store the triangles into m_bed.m_triangles, + // fills the m_bed.m_grid_lines and sets m_bed.m_origin. + // Sets m_bed.m_polygon to limit the object placement. + void set_bed_shape(const Pointfs& shape); + private: bool init_object_menu(); bool init_common_menu(wxMenu* menu, const bool is_part = false); @@ -1127,9 +1200,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D = new View3D(q, &model, config, &background_process); preview = new Preview(q, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); - // Let the Tab key switch between the 3D view and the layer preview. - view3D->Bind(wxEVT_NAVIGATION_KEY, [this](wxNavigationKeyEvent &evt) { if (evt.IsFromTab()) this->select_next_view_3D(); }); - preview->Bind(wxEVT_NAVIGATION_KEY, [this](wxNavigationKeyEvent &evt) { if (evt.IsFromTab()) this->select_next_view_3D(); }); + + view3D->set_bed(&bed); + preview->set_bed(&bed); panels.push_back(view3D); panels.push_back(preview); @@ -1137,12 +1210,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->background_process_timer.SetOwner(this->q, 0); this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->update_restart_background_process(false, false); }); -#if !ENABLE_REWORKED_BED_SHAPE_CHANGE - auto *bed_shape = config->opt("bed_shape"); - view3D->set_bed_shape(bed_shape->values); - preview->set_bed_shape(bed_shape->values); -#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE - update(); auto *hsizer = new wxBoxSizer(wxHORIZONTAL); @@ -1182,6 +1249,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event &evt) { this->sidebar->enable_buttons(evt.data); }); view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this); view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, &priv::on_3dcanvas_mouse_dragging_finished, this); + view3D_canvas->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); }); // 3DScene/Toolbar: view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); }); @@ -1193,10 +1261,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this); view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this); view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); }); + view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&) { set_bed_shape(config->option("bed_shape")->values); }); // Preview events: preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); }); + preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&) { set_bed_shape(config->option("bed_shape")->values); }); + preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); }); view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); }); @@ -1785,7 +1856,7 @@ void Plater::priv::arrange() assert(bed_shape_opt); auto& bedpoints = bed_shape_opt->values; Polyline bed; bed.points.reserve(bedpoints.size()); - for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1))); + for (auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1))); statusfn(0, arrangestr); @@ -1921,10 +1992,14 @@ void Plater::priv::split_volume() void Plater::priv::schedule_background_process() { + delayed_error_message.clear(); // Trigger the timer event after 0.5s this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); // Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff. this->view3D->get_canvas3d()->set_config(this->config); + // Reset gcode preview + this->preview->get_canvas3d()->reset_volumes(); + this->preview->get_canvas3d()->reset_legend_texture(); } void Plater::priv::update_print_volume_state() @@ -1948,6 +2023,8 @@ unsigned int Plater::priv::update_background_process(bool force_validation) this->background_process_timer.Stop(); // Update the "out of print bed" state of ModelInstances. this->update_print_volume_state(); + // The delayed error message is no more valid. + this->delayed_error_message.clear(); // Apply new config to the possibly running background task. bool was_running = this->background_process.running(); Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config()); @@ -1986,8 +2063,18 @@ unsigned int Plater::priv::update_background_process(bool force_validation) return_state |= UPDATE_BACKGROUND_PROCESS_RESTART; } else { // The print is not valid. - // The error returned from the Print needs to be translated into the local language. - GUI::show_error(this->q, _(err)); + // Only show the error message immediately, if the top level parent of this window is active. + auto p = dynamic_cast(this->q); + while (p->GetParent()) + p = p->GetParent(); + auto *top_level_wnd = dynamic_cast(p); + if (top_level_wnd && top_level_wnd->IsActive()) { + // The error returned from the Print needs to be translated into the local language. + GUI::show_error(this->q, _(err)); + } else { + // Show the error message once the main window gets activated. + this->delayed_error_message = _(err); + } return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; } } @@ -2001,6 +2088,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation) wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone()); } + //FIXME update "Slice Now / Schedule background process" + //background_process.is_export_scheduled() - byl zavolan "Export G-code", background processing ma jmeno export souboru + //background_process.is_upload_scheduled() - byl zavolan "Send to OctoPrint", jeste nebylo doslajsovano (pak se preda upload fronte a background process zapomene) + //background_process.empty() - prazdna plocha + // pokud (return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0 -> doslo k chybe (gray out "Slice now") mozna "Invalid data"??? + // jinak background_process.running() -> Zobraz "Slicing ..." + // jinak pokud ! background_process.empty() && ! background_process.finished() -> je neco ke slajsovani (povol tlacitko) "Slice Now" + return return_state; } @@ -2050,6 +2145,8 @@ void Plater::priv::export_gcode(fs::path output_path, PrintHostJob upload_job) background_process.schedule_upload(std::move(upload_job)); } + // If the SLA processing of just a single object's supports is running, restart slicing for the whole object. + this->background_process.set_task(PrintBase::TaskParams()); this->restart_background_process(priv::UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT); } @@ -2167,7 +2264,8 @@ void Plater::priv::set_current_panel(wxPanel* panel) else if (current_panel == preview) { this->q->reslice(); - preview->reload_print(); + // keeps current gcode preview, if any + preview->reload_print(false, true); preview->set_canvas_as_dirty(); view_toolbar.select_item("Preview"); } @@ -2232,6 +2330,10 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) break; } } + if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS) { + // Update SLA gizmo (reload_scene calls update_gizmos_data) + q->canvas3D()->reload_scene(true); + } } void Plater::priv::on_slicing_completed(wxCommandEvent &) @@ -2353,8 +2455,15 @@ void Plater::priv::on_right_click(Vec2dEvent& evt) sidebar->obj_list()->append_menu_item_settings(menu); - if (q != nullptr) + if (q != nullptr) { +#ifdef __linux__ + // For some reason on Linux the menu isn't displayed if position is specified + // (even though the position is sane). + q->PopupMenu(menu); +#else q->PopupMenu(menu, (int)evt.data.x(), (int)evt.data.y()); +#endif + } } void Plater::priv::on_wipetower_moved(Vec3dEvent &evt) @@ -2631,6 +2740,16 @@ bool Plater::priv::can_mirror() const return get_selection().is_from_single_instance(); } +void Plater::priv::set_bed_shape(const Pointfs& shape) +{ + bool new_shape = bed.set_shape(shape); + if (new_shape) + { + if (view3D) view3D->bed_shape_changed(); + if (preview) preview->bed_shape_changed(); + } +} + void Plater::priv::update_object_menu() { sidebar->obj_list()->append_menu_items_add_volume(&object_menu); @@ -2857,7 +2976,7 @@ void Plater::export_gcode() default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")), + wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), start_dir, from_path(default_output_file.filename()), GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), @@ -2885,6 +3004,8 @@ void Plater::export_stl(bool selection_only) const wxString path = dialog->GetPath(); const std::string path_u8 = into_u8(path); + wxBusyCursor wait; + TriangleMesh mesh; if (selection_only) { const auto &selection = p->get_selection(); @@ -2960,10 +3081,38 @@ void Plater::reslice() unsigned int state = this->p->update_background_process(true); if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) this->p->view3D->reload_scene(false); + // If the SLA processing of just a single object's supports is running, restart slicing for the whole object. + this->p->background_process.set_task(PrintBase::TaskParams()); // Only restarts if the state is valid. this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART); } +void Plater::reslice_SLA_supports(const ModelObject &object) +{ + //FIXME Don't reslice if export of G-code or sending to OctoPrint is running. + // bitmask of UpdateBackgroundProcessReturnState + unsigned int state = this->p->update_background_process(true); + if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) + this->p->view3D->reload_scene(false); + + if (this->p->background_process.empty() || (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)) + // Nothing to do on empty input or invalid configuration. + return; + + // Limit calculation to the single object only. + PrintBase::TaskParams task; + task.single_model_object = object.id(); + // If the background processing is not enabled, calculate supports just for the single instance. + // Otherwise calculate everything, but start with the provided object. + if (!this->p->background_processing_enabled()) { + task.single_model_instance_only = true; + task.to_object_step = slaposBasePool; + } + this->p->background_process.set_task(task); + // and let the background processing start. + this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART); +} + void Plater::send_gcode() { if (p->model.objects.empty()) { return; } @@ -3024,20 +3173,13 @@ void Plater::on_extruders_change(int num_extruders) void Plater::on_config_change(const DynamicPrintConfig &config) { bool update_scheduled = false; -#if ENABLE_REWORKED_BED_SHAPE_CHANGE bool bed_shape_changed = false; -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE for (auto opt_key : p->config->diff(config)) { p->config->set_key_value(opt_key, config.option(opt_key)->clone()); if (opt_key == "printer_technology") this->set_printer_technology(config.opt_enum(opt_key)); else if (opt_key == "bed_shape") { -#if ENABLE_REWORKED_BED_SHAPE_CHANGE bed_shape_changed = true; -#else - if (p->view3D) p->view3D->set_bed_shape(p->config->option(opt_key)->values); - if (p->preview) p->preview->set_bed_shape(p->config->option(opt_key)->values); -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE update_scheduled = true; } else if (boost::starts_with(opt_key, "wipe_tower") || @@ -3063,12 +3205,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) } else if (opt_key == "printer_model") { // update to force bed selection(for texturing) -#if ENABLE_REWORKED_BED_SHAPE_CHANGE bed_shape_changed = true; -#else - if (p->view3D) p->view3D->set_bed_shape(p->config->option("bed_shape")->values); - if (p->preview) p->preview->set_bed_shape(p->config->option("bed_shape")->values); -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE update_scheduled = true; } else if (opt_key == "host_type" && this->p->printer_technology == ptSLA) { @@ -3081,13 +3218,8 @@ void Plater::on_config_change(const DynamicPrintConfig &config) p->sidebar->show_send(prin_host_opt != nullptr && !prin_host_opt->value.empty()); } -#if ENABLE_REWORKED_BED_SHAPE_CHANGE if (bed_shape_changed) - { - if (p->view3D) p->view3D->set_bed_shape(p->config->option("bed_shape")->values); - if (p->preview) p->preview->set_bed_shape(p->config->option("bed_shape")->values); - } -#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE + p->set_bed_shape(p->config->option("bed_shape")->values); if (update_scheduled) update(); @@ -3096,6 +3228,26 @@ void Plater::on_config_change(const DynamicPrintConfig &config) this->p->schedule_background_process(); } +void Plater::on_activate() +{ +#ifdef __linux__ + wxWindow *focus_window = wxWindow::FindFocus(); + // Activating the main frame, and no window has keyboard focus. + // Set the keyboard focus to the visible Canvas3D. + if (this->p->view3D->IsShown() && (!focus_window || focus_window == this->p->view3D->get_wxglcanvas())) + this->p->view3D->get_wxglcanvas()->SetFocus(); + + else if (this->p->preview->IsShown() && (!focus_window || focus_window == this->p->view3D->get_wxglcanvas())) + this->p->preview->get_wxglcanvas()->SetFocus(); +#endif + + if (! this->p->delayed_error_message.empty()) { + std::string msg = std::move(this->p->delayed_error_message); + this->p->delayed_error_message.clear(); + GUI::show_error(this, msg); + } +} + const wxString& Plater::get_project_filename() const { return p->project_filename; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index e3601b65c..4d489c82a 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -10,6 +10,9 @@ #include "Preset.hpp" +#include "3DScene.hpp" +#include "GLTexture.hpp" + class wxButton; class wxBoxSizer; class wxGLCanvas; @@ -19,6 +22,7 @@ class wxString; namespace Slic3r { class Model; +class ModelObject; class Print; class SLAPrint; @@ -145,12 +149,15 @@ public: void export_amf(); void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); void reslice(); + void reslice_SLA_supports(const ModelObject &object); void changed_object(int obj_idx); void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); void send_gcode(); void on_extruders_change(int extruders_count); void on_config_change(const DynamicPrintConfig &config); + // On activating the parent window. + void on_activate(); void update_object_menu(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index b58ce5900..5ce65b669 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -15,7 +15,7 @@ void PreferencesDialog::build() { auto app_config = get_app_config(); m_optgroup = std::make_shared(this, _(L("General"))); - m_optgroup->label_width = 400; + m_optgroup->label_width = 40 * wxGetApp().em_unit(); //400; m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){ m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index ca6c8512f..bb378ae6c 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -11,8 +11,10 @@ #include #endif /* _MSC_VER */ +#include #include #include +#include #include #include #include @@ -83,6 +85,16 @@ VendorProfile VendorProfile::from_ini(const boost::filesystem::path &path, bool return VendorProfile::from_ini(tree, path, load_all); } +static const std::unordered_map pre_family_model_map {{ + { "MK3", "MK3" }, + { "MK3MMU2", "MK3" }, + { "MK2.5", "MK2.5" }, + { "MK2.5MMU2", "MK2.5" }, + { "MK2S", "MK2" }, + { "MK2SMM", "MK2" }, + { "SL1", "SL1" }, +}}; + VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem::path &path, bool load_all) { static const std::string printer_model_key = "printer_model:"; @@ -128,11 +140,21 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem VendorProfile::PrinterModel model; model.id = section.first.substr(printer_model_key.size()); model.name = section.second.get("name", model.id); - auto technology_field = section.second.get("technology", "FFF"); + + const char *technology_fallback = boost::algorithm::starts_with(model.id, "SL") ? "SLA" : "FFF"; + + auto technology_field = section.second.get("technology", technology_fallback); if (! ConfigOptionEnum::from_string(technology_field, model.technology)) { BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Invalid printer technology field: `%2%`") % id % technology_field; model.technology = ptFFF; } + + model.family = section.second.get("family", std::string()); + if (model.family.empty() && res.name == "Prusa Research") { + // If no family is specified, it can be inferred for known printers + const auto from_pre_map = pre_family_model_map.find(model.id); + if (from_pre_map != pre_family_model_map.end()) { model.family = from_pre_map->second; } + } #if 0 // Remove SLA printers from the initial alpha. if (model.technology == ptSLA) @@ -157,6 +179,20 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem return res; } +std::vector VendorProfile::families() const +{ + std::vector res; + unsigned num_familiies = 0; + + for (auto &model : models) { + if (std::find(res.begin(), res.end(), model.family) == res.end()) { + res.push_back(model.family); + num_familiies++; + } + } + + return res; +} // Suffix to be added to a modified preset name in the combo box. static std::string g_suffix_modified = " (modified)"; @@ -318,7 +354,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config) const std::vector& Preset::print_options() { static std::vector s_opts { - "layer_height", "first_layer_height", "perimeters", "spiral_vase", "top_solid_layers", "bottom_solid_layers", + "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "top_solid_layers", "bottom_solid_layers", "extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs", "seam_position", "external_perimeters_first", "fill_density" , "fill_pattern" @@ -362,7 +398,6 @@ const std::vector& Preset::print_options() , "perimeter_loop" , "perimeter_loop_seam" , "seam_travel" - , "remove_small_gaps" , "infill_not_connected" , "first_layer_infill_speed" , "thin_walls_min_width" @@ -441,6 +476,7 @@ const std::vector& Preset::sla_print_options() if (s_opts.empty()) { s_opts = { "layer_height", + "faded_layers", "supports_enable", "support_head_front_diameter", "support_head_penetration", @@ -454,14 +490,15 @@ const std::vector& Preset::sla_print_options() "support_critical_angle", "support_max_bridge_length", "support_object_elevation", - "support_density_at_horizontal", - "support_density_at_45", - "support_minimal_z", + "support_points_density_relative", + "support_points_minimal_distance", + "slice_closing_radius", "pad_enable", "pad_wall_thickness", "pad_wall_height", "pad_max_merge_distance", "pad_edge_radius", + "pad_wall_slope", "output_filename_format", "default_sla_print_profile", "compatible_printers", @@ -498,6 +535,7 @@ const std::vector& Preset::sla_printer_options() "bed_shape", "max_print_height", "display_width", "display_height", "display_pixels_x", "display_pixels_y", "display_orientation", + "fast_tilt_time", "slow_tilt_time", "area_fill", "printer_correction", "print_host", "printhost_apikey", "printhost_cafile", "printer_notes", diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 73a921cf7..074e665c9 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -54,13 +54,16 @@ public: std::string id; std::string name; PrinterTechnology technology; + std::string family; std::vector variants; + PrinterVariant* variant(const std::string &name) { for (auto &v : this->variants) if (v.name == name) return &v; return nullptr; } + const PrinterVariant* variant(const std::string &name) const { return const_cast(this)->variant(name); } }; std::vector models; @@ -72,6 +75,7 @@ public: static VendorProfile from_ini(const boost::property_tree::ptree &tree, const boost::filesystem::path &path, bool load_all=true); size_t num_variants() const { size_t n = 0; for (auto &model : models) n += model.variants.size(); return n; } + std::vector families() const; bool operator< (const VendorProfile &rhs) const { return this->id < rhs.id; } bool operator==(const VendorProfile &rhs) const { return this->id == rhs.id; } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index f8cba6004..bf166143c 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -1435,7 +1435,8 @@ bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui) { - if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA) + if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA || + this->filament_presets.size() <= idx_extruder ) return; unsigned char rgb[3]; diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index d6b5f3469..1ec1c3a6a 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -15,6 +15,7 @@ #include "GUI.hpp" #include "GUI_App.hpp" +#include "AppConfig.hpp" #include "MsgDialog.hpp" #include "I18N.hpp" #include "../Utils/PrintHost.hpp" @@ -24,10 +25,12 @@ namespace fs = boost::filesystem; namespace Slic3r { namespace GUI { +static const char *CONFIG_KEY_PATH = "printhost_path"; +static const char *CONFIG_KEY_PRINT = "printhost_print"; PrintHostSendDialog::PrintHostSendDialog(const fs::path &path) : MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE) - , txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())) + , txt_filename(new wxTextCtrl(this, wxID_ANY)) , box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload")))) { #ifdef __APPLE__ @@ -35,7 +38,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path) #endif auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed."))); - label_dir_hint->Wrap(CONTENT_WIDTH); + label_dir_hint->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(txt_filename, 0, wxEXPAND); content_sizer->Add(label_dir_hint); @@ -44,11 +47,30 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path) btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL)); - txt_filename->SetFocus(); + const AppConfig *app_config = wxGetApp().app_config; + box_print->SetValue(app_config->get("recent", CONFIG_KEY_PRINT) == "1"); + + wxString recent_path = from_u8(app_config->get("recent", CONFIG_KEY_PATH)); + if (recent_path.Length() > 0 && recent_path[recent_path.Length() - 1] != '/') { + recent_path += '/'; + } + const auto recent_path_len = recent_path.Length(); + recent_path += path.filename().wstring(); wxString stem(path.stem().wstring()); - txt_filename->SetSelection(0, stem.Length()); + const auto stem_len = stem.Length(); + + txt_filename->SetValue(recent_path); + txt_filename->SetFocus(); Fit(); + + Bind(wxEVT_SHOW, [=](const wxShowEvent &) { + // Another similar case where the function only works with EVT_SHOW + CallAfter, + // this time on Mac. + CallAfter([=]() { + txt_filename->SetSelection(recent_path_len, recent_path_len + stem_len); + }); + }); } fs::path PrintHostSendDialog::filename() const @@ -61,6 +83,24 @@ bool PrintHostSendDialog::start_print() const return box_print->GetValue(); } +void PrintHostSendDialog::EndModal(int ret) +{ + if (ret == wxID_OK) { + // Persist path and print settings + wxString path = txt_filename->GetValue(); + int last_slash = path.Find('/', true); + if (last_slash != wxNOT_FOUND) { + path = path.SubString(0, last_slash); + wxGetApp().app_config->set("recent", CONFIG_KEY_PATH, into_u8(path)); + } + + bool print = box_print->GetValue(); + GUI::get_app_config()->set("recent", CONFIG_KEY_PRINT, print ? "1" : "0"); + } + + MsgDialog::EndModal(ret); +} + wxDEFINE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event); @@ -95,10 +135,11 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) , on_error_evt(this, EVT_PRINTHOST_ERROR, &PrintHostQueueDialog::on_error, this) , on_cancel_evt(this, EVT_PRINTHOST_CANCEL, &PrintHostQueueDialog::on_cancel, this) { - enum { HEIGHT = 800, WIDTH = 400, SPACING = 5 }; + enum { HEIGHT = 60, WIDTH = 30, SPACING = 5 }; - SetSize(wxSize(HEIGHT, WIDTH)); - SetSize(GetMinSize()); + const auto em = GetTextExtent("m").x; + + SetSize(wxSize(HEIGHT * em, WIDTH * em)); auto *topsizer = new wxBoxSizer(wxVERTICAL); @@ -116,7 +157,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) btn_cancel->Disable(); btn_error = new wxButton(this, wxID_ANY, _(L("Show error message"))); btn_error->Disable(); - auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); + auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING); btnsizer->Add(btn_error, 0); btnsizer->AddStretchSpacer(); diff --git a/src/slic3r/GUI/PrintHostDialogs.hpp b/src/slic3r/GUI/PrintHostDialogs.hpp index ee3fe26d8..e7c84fefd 100644 --- a/src/slic3r/GUI/PrintHostDialogs.hpp +++ b/src/slic3r/GUI/PrintHostDialogs.hpp @@ -33,6 +33,7 @@ public: boost::filesystem::path filename() const; bool start_print() const; + virtual void EndModal(int ret) override; private: wxTextCtrl *txt_filename; wxCheckBox *box_print; diff --git a/src/slic3r/GUI/RammingChart.cpp b/src/slic3r/GUI/RammingChart.cpp index cbf660f2c..41e5cdfe7 100644 --- a/src/slic3r/GUI/RammingChart.cpp +++ b/src/slic3r/GUI/RammingChart.cpp @@ -20,7 +20,7 @@ void Chart::draw() { dc.DrawRectangle(m_rect); if (visible_area.m_width < 0.499) { - dc.DrawText(_(L("NO RAMMING AT ALL")),wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-50,m_rect.GetBottom()-m_rect.GetHeight()/2)); + dc.DrawText(_(L("NO RAMMING AT ALL")),wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-legend_side,m_rect.GetBottom()-m_rect.GetHeight()/2)); return; } @@ -55,9 +55,9 @@ void Chart::draw() { for (float math_x=int(visible_area.m_x*10)/10 ; math_x < (visible_area.m_x+visible_area.m_width) ; math_x+=0.1f) { int x = math_to_screen(wxPoint2DDouble(math_x,visible_area.m_y)).x; int y = m_rect.GetBottom(); - if (x-last_mark < 50) continue; + if (x-last_mark < legend_side) continue; dc.DrawLine(x,y+3,x,y-3); - dc.DrawText(wxString().Format(wxT("%.1f"), math_x),wxPoint(x-10,y+7)); + dc.DrawText(wxString().Format(wxT("%.1f"), math_x),wxPoint(x-scale_unit,y+0.5*scale_unit)); last_mark = x; } @@ -66,9 +66,9 @@ void Chart::draw() { for (int math_y=visible_area.m_y ; math_y < (visible_area.m_y+visible_area.m_height) ; math_y+=1) { int y = math_to_screen(wxPoint2DDouble(visible_area.m_x,math_y)).y; int x = m_rect.GetLeft(); - if (last_mark-y < 50) continue; + if (last_mark-y < legend_side) continue; dc.DrawLine(x-3,y,x+3,y); - dc.DrawText(wxString()<>& initial_buttons,int ramming_speed_size, float sampling) : - wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize()) + Chart(wxWindow* parent, wxRect rect,const std::vector>& initial_buttons,int ramming_speed_size, float sampling, int scale_unit=10) : + wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize()), + scale_unit(scale_unit), legend_side(5*scale_unit) { SetBackgroundStyle(wxBG_STYLE_PAINT); - m_rect = wxRect(wxPoint(50,0),rect.GetSize()-wxSize(50,50)); + m_rect = wxRect(wxPoint(legend_side,0),rect.GetSize()-wxSize(legend_side,legend_side)); visible_area = wxRect2DDouble(0.0, 0.0, sampling*ramming_speed_size, 20.); m_buttons.clear(); if (initial_buttons.size()>0) @@ -49,6 +50,7 @@ public: DECLARE_EVENT_TABLE() + private: static const bool fixed_x = true; @@ -56,6 +58,9 @@ private: static const bool manual_points_manipulation = false; static const int side = 10; // side of draggable button + const int scale_unit; + int legend_side; + class ButtonToDrag { public: bool operator<(const ButtonToDrag& a) const { return m_pos.m_x < a.m_pos.m_x; } diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index fd8ab5f93..dfaba71ae 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -3,8 +3,12 @@ #include "3DScene.hpp" #include "GUI.hpp" +#include + #include #include +#include "GUI_App.hpp" +#include "wxExtensions.hpp" namespace Slic3r { namespace GUI { @@ -42,15 +46,16 @@ SysInfoDialog::SysInfoDialog() wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); SetBackgroundColour(bgr_clr); wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL); - hsizer->SetMinSize(wxSize(600, -1)); + hsizer->SetMinSize(wxSize(50 * wxGetApp().em_unit(), -1)); auto main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 10); + main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10); // logo - wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG); - auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(logo_bmp)); - hsizer->Add(logo, 0, wxEXPAND | wxTOP | wxBOTTOM, 15); +// wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG); +// auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(logo_bmp)); + auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png")); + hsizer->Add(logo, 0, wxALIGN_CENTER_VERTICAL); wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); hsizer->Add(vsizer, 1, wxEXPAND|wxLEFT, 20); @@ -63,7 +68,7 @@ SysInfoDialog::SysInfoDialog() title_font.SetFamily(wxFONTFAMILY_ROMAN); title_font.SetPointSize(22); title->SetFont(title_font); - vsizer->Add(title, 0, wxALIGN_LEFT | wxTOP, 50); + vsizer->Add(title, 0, wxEXPAND | wxALIGN_LEFT | wxTOP, wxGetApp().em_unit()/*50*/); } // main_info_text @@ -89,13 +94,13 @@ SysInfoDialog::SysInfoDialog() "", bgr_clr_str, text_clr_str, text_clr_str, get_main_info(true)); html->SetPage(text); - vsizer->Add(html, 1, wxEXPAND); + vsizer->Add(html, 1, wxEXPAND | wxBOTTOM, wxGetApp().em_unit()); } // opengl_info wxHtmlWindow* opengl_info_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); { - opengl_info_html->SetMinSize(wxSize(-1, 200)); + opengl_info_html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit())); opengl_info_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); opengl_info_html->SetBorders(10); const auto text = wxString::Format( diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b939683a3..1d54b65b0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -56,6 +56,8 @@ Tab::Tab(wxNotebook* parent, const wxString& title, const char* name) : m_compatible_prints.dialog_label = _(L("Select the print profiles this profile is compatible with.")); wxGetApp().tabs_list.push_back(this); + + m_em_unit = wxGetApp().em_unit(); } void Tab::set_type() @@ -96,22 +98,26 @@ void Tab::create_preset_tab() #endif //__WXOSX__ // preset chooser - m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY); + m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(25 * m_em_unit, -1), 0, 0, wxCB_READONLY); auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //buttons wxBitmap bmpMenu; - bmpMenu = wxBitmap(from_u8(Slic3r::var("disk.png")), wxBITMAP_TYPE_PNG); +// bmpMenu = wxBitmap(from_u8(Slic3r::var("disk.png")), wxBITMAP_TYPE_PNG); + bmpMenu = create_scaled_bitmap("disk.png"); m_btn_save_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); if (wxMSW) m_btn_save_preset->SetBackgroundColour(color); - bmpMenu = wxBitmap(from_u8(Slic3r::var("delete.png")), wxBITMAP_TYPE_PNG); +// bmpMenu = wxBitmap(from_u8(Slic3r::var("delete.png")), wxBITMAP_TYPE_PNG); + bmpMenu = create_scaled_bitmap("delete.png"); m_btn_delete_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); if (wxMSW) m_btn_delete_preset->SetBackgroundColour(color); m_show_incompatible_presets = false; - m_bmp_show_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG); - m_bmp_hide_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG); +// m_bmp_show_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG); +// m_bmp_hide_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG); + m_bmp_show_incompatible_presets = create_scaled_bitmap("flag-red-icon.png"); + m_bmp_hide_incompatible_presets = create_scaled_bitmap("flag-green-icon.png"); m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); if (wxMSW) m_btn_hide_incompatible_presets->SetBackgroundColour(color); @@ -134,13 +140,18 @@ void Tab::create_preset_tab() // Determine the theme color of OS (dark or light) auto luma = wxGetApp().get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); // Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field. - m_bmp_value_lock .LoadFile(from_u8(var("sys_lock.png")), wxBITMAP_TYPE_PNG); - m_bmp_value_unlock .LoadFile(from_u8(var(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png")), wxBITMAP_TYPE_PNG); +// m_bmp_value_lock .LoadFile(from_u8(var("sys_lock.png")), wxBITMAP_TYPE_PNG); +// m_bmp_value_unlock .LoadFile(from_u8(var(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png")), wxBITMAP_TYPE_PNG); + m_bmp_value_lock = create_scaled_bitmap("sys_lock.png"); + m_bmp_value_unlock = create_scaled_bitmap(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png"); m_bmp_non_system = &m_bmp_white_bullet; // Bitmaps to be shown on the "Undo user changes" button next to each input field. - m_bmp_value_revert .LoadFile(from_u8(var(luma >= 128 ? "action_undo.png" : "action_undo_grey.png")), wxBITMAP_TYPE_PNG); - m_bmp_white_bullet .LoadFile(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG); - m_bmp_question .LoadFile(from_u8(var("question_mark_01.png")), wxBITMAP_TYPE_PNG); +// m_bmp_value_revert .LoadFile(from_u8(var(luma >= 128 ? "action_undo.png" : "action_undo_grey.png")), wxBITMAP_TYPE_PNG); +// m_bmp_white_bullet .LoadFile(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG); +// m_bmp_question .LoadFile(from_u8(var("question_mark_01.png")), wxBITMAP_TYPE_PNG); + m_bmp_value_revert = create_scaled_bitmap(luma >= 128 ? "action_undo.png" : "action_undo_grey.png"); + m_bmp_white_bullet = create_scaled_bitmap("bullet_white.png"); + m_bmp_question = create_scaled_bitmap("question_mark_01.png"); fill_icon_descriptions(); set_tooltips_text(); @@ -171,19 +182,20 @@ void Tab::create_preset_tab() // Sizer with buttons for mode changing m_mode_sizer = new PrusaModeSizer(panel); + const float scale_factor = wxGetApp().em_unit()*0.1;// GetContentScaleFactor(); m_hsizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_hsizer, 0, wxEXPAND | wxBOTTOM, 3); m_hsizer->Add(m_presets_choice, 0, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3); - m_hsizer->AddSpacer(4); + m_hsizer->AddSpacer(int(4*scale_factor)); m_hsizer->Add(m_btn_save_preset, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(4); + m_hsizer->AddSpacer(int(4 * scale_factor)); m_hsizer->Add(m_btn_delete_preset, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(16); + m_hsizer->AddSpacer(int(16 * scale_factor)); m_hsizer->Add(m_btn_hide_incompatible_presets, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(64); + m_hsizer->AddSpacer(int(64 * scale_factor)); m_hsizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); m_hsizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(32); + m_hsizer->AddSpacer(int(32 * scale_factor)); m_hsizer->Add(m_question_btn, 0, wxALIGN_CENTER_VERTICAL); // m_hsizer->AddStretchSpacer(32); // StretchSpacer has a strange behavior under OSX, so @@ -201,10 +213,10 @@ void Tab::create_preset_tab() m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3); // tree - m_treectrl = new wxTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(185, -1), + m_treectrl = new wxTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(20 * m_em_unit, -1), wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_SUNKEN | wxWANTS_CHARS); m_left_sizer->Add(m_treectrl, 1, wxEXPAND); - m_icons = new wxImageList(16, 16, true, 1); + m_icons = new wxImageList(int(16 * scale_factor), int(16 * scale_factor), true, 1); // Index of the last icon inserted into $self->{icons}. m_icon_count = -1; m_treectrl->AssignImageList(m_icons); @@ -263,8 +275,9 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str icon_idx = (m_icon_index.find(icon) == m_icon_index.end()) ? -1 : m_icon_index.at(icon); if (icon_idx == -1) { // Add a new icon to the icon list. - wxIcon img_icon(from_u8(Slic3r::var(icon)), wxBITMAP_TYPE_PNG); - m_icons->Add(img_icon); +// wxIcon img_icon(from_u8(Slic3r::var(icon)), wxBITMAP_TYPE_PNG); +// m_icons->Add(img_icon); + m_icons->Add(create_scaled_bitmap(icon)); icon_idx = ++m_icon_count; m_icon_index[icon] = icon_idx; } @@ -740,18 +753,6 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo void Tab::on_value_change(const std::string& opt_key, const boost::any& value) { - wxCommandEvent event(EVT_TAB_VALUE_CHANGED); - event.SetEventObject(this); - event.SetString(opt_key); - if (opt_key == "extruders_count") - { - int val = boost::any_cast(value); - event.SetInt(val); - } - - wxPostEvent(this, event); - - ConfigOptionsGroup* og_freq_chng_params = wxGetApp().sidebar().og_freq_chng_params(supports_printer_technology(ptFFF)); if (opt_key == "fill_density" || opt_key == "supports_enable" || opt_key == "pad_enable") { @@ -776,7 +777,29 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (opt_key == "wipe_tower" || opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" ) update_wiping_button_visibility(); + if (opt_key == "extruders_count") + wxGetApp().plater()->on_extruders_change(boost::any_cast(value)); + update(); + + // #ys_FIXME_to_delete + // Post event to the Plater after updating of the all dirty options + // It helps to avoid needless schedule_background_processing +// if (update_completed()) +// if (m_update_stack.empty()) +// { +// // wxCommandEvent event(EVT_TAB_VALUE_CHANGED); +// // event.SetEventObject(this); +// // event.SetString(opt_key); +// // if (opt_key == "extruders_count") +// // { +// // const int val = boost::any_cast(value); +// // event.SetInt(val); +// // } +// // +// // wxPostEvent(this, event); +// wxGetApp().mainframe->on_value_changed(m_config); +// } } // Show/hide the 'purging volumes' button @@ -809,10 +832,18 @@ void Tab::on_presets_changed() // refresh the print or filament/sla_material tab page. wxGetApp().get_tab(t)->load_current_preset(); } + // clear m_dependent_tabs after first update from select_preset() + // to avoid needless preset loading from update() function + m_dependent_tabs.clear(); + + // #ys_FIXME_to_delete +// wxCommandEvent event(EVT_TAB_PRESETS_CHANGED); +// event.SetEventObject(this); +// wxPostEvent(this, event); + + // Instead of PostEvent (EVT_TAB_PRESETS_CHANGED) just call update_presets + wxGetApp().plater()->sidebar().update_presets(m_type); - wxCommandEvent event(EVT_TAB_PRESETS_CHANGED); - event.SetEventObject(this); - wxPostEvent(this, event); update_preset_description_line(); } @@ -955,7 +986,6 @@ void TabPrint::build() optgroup->append_single_option_line("no_perimeter_unsupported_algo"); optgroup = page->new_optgroup(_(L("Advanced"))); - optgroup->append_single_option_line("remove_small_gaps"); line = { _(L("Seam")), "" }; line.append_option(optgroup->get_option("seam_position")); line.append_option(optgroup->get_option("seam_travel")); @@ -1137,14 +1167,17 @@ void TabPrint::build() line.append_option(optgroup->get_option("over_bridge_flow_ratio")); optgroup->append_line(line); - optgroup = page->new_optgroup(_(L("Other"))); - optgroup->append_single_option_line("clip_multipart_objects"); + optgroup = page->new_optgroup(_(L("Slicing"))); + optgroup->append_single_option_line("slice_closing_radius"); + optgroup->append_single_option_line("resolution"); line = { _(L("XY compensation")), "" }; line.append_option(optgroup->get_option("xy_size_compensation")); line.append_option(optgroup->get_option("elefant_foot_compensation")); line.append_option(optgroup->get_option("hole_size_compensation")); optgroup->append_line(line); -// # optgroup->append_single_option_line("threads"); + + optgroup = page->new_optgroup(_(L("Other"))); + optgroup->append_single_option_line("clip_multipart_objects"); optgroup->append_single_option_line("resolution"); page = add_options_page(_(L("Output options")), "page_white_go.png"); @@ -1169,14 +1202,14 @@ void TabPrint::build() optgroup = page->new_optgroup(_(L("Post-processing scripts")), 0); option = optgroup->get_option("post_process"); option.opt.full_width = true; - option.opt.height = 50; + option.opt.height = 5 * m_em_unit;//50; optgroup->append_single_option_line(option); page = add_options_page(_(L("Notes")), "note.png"); optgroup = page->new_optgroup(_(L("Notes")), 0); option = optgroup->get_option("notes"); option.opt.full_width = true; - option.opt.height = 250; + option.opt.height = 25 * m_em_unit;//250; optgroup->append_single_option_line(option); page = add_options_page(_(L("Dependencies")), "wrench.png"); @@ -1210,13 +1243,15 @@ void TabPrint::update() if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME + // #ys_FIXME_to_delete //! Temporary workaround for the correct updates of the SpinCtrl (like "perimeters"): // KillFocus() for the wxSpinCtrl use CallAfter function. So, // to except the duplicate call of the update() after dialog->ShowModal(), // let check if this process is already started. - if (is_msg_dlg_already_exist) - return; +// if (is_msg_dlg_already_exist) // ! It looks like a fixed problem after start to using of a m_dirty_options +// return; // ! TODO Let delete this part of code after a common aplication testing + m_update_cnt++; Freeze(); double fill_density = m_config->option("fill_density")->value; @@ -1243,7 +1278,7 @@ void TabPrint::update() "- unchecked 'extra perimeters'\n" "\nShall I adjust those settings in order to enable Spiral Vase?")); auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); - is_msg_dlg_already_exist = true; +// is_msg_dlg_already_exist = true; DynamicPrintConfig new_conf = *m_config; if (dialog->ShowModal() == wxID_YES) { new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); @@ -1262,7 +1297,7 @@ void TabPrint::update() } load_config(new_conf); on_value_change("fill_density", fill_density); - is_msg_dlg_already_exist = false; +// is_msg_dlg_already_exist = false; } if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") && @@ -1350,12 +1385,6 @@ void TabPrint::update() for (const std::string &fill : bottom_fill_pattern) { if (str_fill_pattern.compare(fill) == 0) correct_100p_fill = true; - } - //note: supermerill : i don't understand this but i copy-paste - const std::vector solid_fill_pattern = m_config->def()->get("solid_fill_pattern")->enum_values; - for (const std::string &fill : solid_fill_pattern) { - if (str_fill_pattern.compare(fill) == 0) - correct_100p_fill = true; } // get fill_pattern name from enum_labels for using this one at dialog_msg str_fill_pattern = m_config->def()->get("fill_pattern")->enum_labels[fill_pattern]; @@ -1471,6 +1500,10 @@ void TabPrint::update() from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle))); Thaw(); + m_update_cnt--; + + if (m_update_cnt==0) + wxGetApp().mainframe->on_config_changed(m_config); } void TabPrint::OnActivate() @@ -1577,18 +1610,20 @@ void TabFilament::build() }; optgroup->append_line(line); + const int gcode_field_height = 15 * m_em_unit; // 150 + const int notes_field_height = 25 * m_em_unit; // 250 page = add_options_page(_(L("Custom G-code")), "cog.png"); optgroup = page->new_optgroup(_(L("Start G-code")), 0); Option option = optgroup->get_option("start_filament_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;// 150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(_(L("End G-code")), 0); option = optgroup->get_option("end_filament_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;// 150; optgroup->append_single_option_line(option); page = add_options_page(_(L("Notes")), "note.png"); @@ -1596,7 +1631,7 @@ void TabFilament::build() optgroup->label_width = 0; option = optgroup->get_option("filament_notes"); option.opt.full_width = true; - option.opt.height = 250; + option.opt.height = notes_field_height;// 250; optgroup->append_single_option_line(option); page = add_options_page(_(L("Dependencies")), "wrench.png"); @@ -1641,6 +1676,7 @@ void TabFilament::update() if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME + m_update_cnt++; Freeze(); wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset())); m_cooling_description_line->SetText(text); @@ -1656,6 +1692,10 @@ void TabFilament::update() for (auto el : { "min_fan_speed", "disable_fan_first_layers" }) get_field(el)->toggle(fan_always_on); Thaw(); + m_update_cnt--; + + if (m_update_cnt == 0) + wxGetApp().mainframe->on_config_changed(m_config); } void TabFilament::OnActivate() @@ -1697,7 +1737,8 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) // TODO: SLA Bonjour auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); - btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); +// btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); + btn->SetBitmap(create_scaled_bitmap("zoom.png")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -1715,7 +1756,8 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) auto print_host_test = [this](wxWindow* parent) { auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")), wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); - btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("wrench.png")), wxBITMAP_TYPE_PNG)); +// btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("wrench.png")), wxBITMAP_TYPE_PNG)); + btn->SetBitmap(create_scaled_bitmap("wrench.png")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -1751,7 +1793,8 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) { auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); - btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); +// btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); + btn->SetBitmap(create_scaled_bitmap("zoom.png")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -1828,7 +1871,8 @@ void TabPrinter::build_fff() line.widget = [this](wxWindow* parent) { auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); btn->SetFont(wxGetApp().small_font()); - btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); +// btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); + btn->SetBitmap(create_scaled_bitmap("printer_empty.png")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -1956,48 +2000,50 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("use_volumetric_e"); optgroup->append_single_option_line("variable_layer_height"); + const int gcode_field_height = 15 * m_em_unit; // 150 + const int notes_field_height = 25 * m_em_unit; // 250 page = add_options_page(_(L("Custom G-code")), "cog.png"); optgroup = page->new_optgroup(_(L("Start G-code")), 0); option = optgroup->get_option("start_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(_(L("End G-code")), 0); option = optgroup->get_option("end_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(_(L("Before layer change G-code")), 0); option = optgroup->get_option("before_layer_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(_(L("After layer change G-code")), 0); option = optgroup->get_option("layer_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(_(L("Tool change G-code")), 0); option = optgroup->get_option("toolchange_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(_(L("Between objects G-code (for sequential printing)")), 0); option = optgroup->get_option("between_objects_gcode"); option.opt.full_width = true; - option.opt.height = 150; + option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); page = add_options_page(_(L("Notes")), "note.png"); optgroup = page->new_optgroup(_(L("Notes")), 0); option = optgroup->get_option("printer_notes"); option.opt.full_width = true; - option.opt.height = 250; + option.opt.height = notes_field_height;//250; optgroup->append_single_option_line(option); page = add_options_page(_(L("Dependencies")), "wrench.png"); @@ -2028,7 +2074,8 @@ void TabPrinter::build_sla() line.widget = [this](wxWindow* parent) { auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); // btn->SetFont(Slic3r::GUI::small_font); - btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); +// btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); + btn->SetBitmap(create_scaled_bitmap("printer_empty.png")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -2059,6 +2106,13 @@ void TabPrinter::build_sla() optgroup->append_line(line); optgroup->append_single_option_line("display_orientation"); + optgroup = page->new_optgroup(_(L("Tilt"))); + line = { _(L("Tilt time")), "" }; + line.append_option(optgroup->get_option("fast_tilt_time")); + line.append_option(optgroup->get_option("slow_tilt_time")); + optgroup->append_line(line); + optgroup->append_single_option_line("area_fill"); + optgroup = page->new_optgroup(_(L("Corrections"))); line = Line{ m_config->def()->get("printer_correction")->full_label, "" }; std::vector axes{ "X", "Y", "Z" }; @@ -2074,11 +2128,13 @@ void TabPrinter::build_sla() optgroup = page->new_optgroup(_(L("Print Host upload"))); build_printhost(optgroup.get()); + const int notes_field_height = 25 * m_em_unit; // 250 + page = add_options_page(_(L("Notes")), "note.png"); optgroup = page->new_optgroup(_(L("Notes")), 0); option = optgroup->get_option("printer_notes"); option.opt.full_width = true; - option.opt.height = 250; + option.opt.height = notes_field_height;//250; optgroup->append_single_option_line(option); page = add_options_page(_(L("Dependencies")), "wrench.png"); @@ -2127,7 +2183,7 @@ PageShp TabPrinter::build_kinematics_page() // Legend for OptionsGroups auto optgroup = page->new_optgroup(""); optgroup->set_show_modified_btns_val(false); - optgroup->label_width = 230; + optgroup->label_width = 23 * m_em_unit;// 230; auto line = Line{ "", "" }; ConfigOptionDef def; @@ -2320,7 +2376,12 @@ void TabPrinter::update_pages() void TabPrinter::update() { + m_update_cnt++; m_presets->get_edited_preset().printer_technology() == ptFFF ? update_fff() : update_sla(); + m_update_cnt--; + + if (m_update_cnt == 0) + wxGetApp().mainframe->on_config_changed(m_config); } void TabPrinter::update_fff() @@ -2914,7 +2975,8 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep deps.checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All"))); deps.btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); - deps.btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); +// deps.btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); + deps.btn->SetBitmap(create_scaled_bitmap("printer_empty.png")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add((deps.checkbox), 0, wxALIGN_CENTER_VERTICAL); @@ -3105,7 +3167,8 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la bmp_name = mode == comExpert ? "mode_expert_.png" : mode == comAdvanced ? "mode_middle_.png" : "mode_simple_.png"; } - auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : wxBitmap(from_u8(var(bmp_name)), wxBITMAP_TYPE_PNG)); +// auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : wxBitmap(from_u8(var(bmp_name)), wxBITMAP_TYPE_PNG)); + auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : create_scaled_bitmap(bmp_name)); return bmp; }; @@ -3223,7 +3286,7 @@ void TabSLAMaterial::build() optgroup->append_single_option_line("initial_exposure_time"); optgroup = page->new_optgroup(_(L("Corrections"))); - optgroup->label_width = 190; + optgroup->label_width = 19 * m_em_unit;//190; std::vector corrections = { "material_correction_printing", "material_correction_curing" }; std::vector axes{ "X", "Y", "Z" }; for (auto& opt_key : corrections) { @@ -3244,7 +3307,7 @@ void TabSLAMaterial::build() optgroup->label_width = 0; Option option = optgroup->get_option("material_notes"); option.opt.full_width = true; - option.opt.height = 250; + option.opt.height = 25 * m_em_unit;//250; optgroup->append_single_option_line(option); page = add_options_page(_(L("Dependencies")), "wrench.png"); @@ -3287,6 +3350,14 @@ void TabSLAMaterial::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) return; // #ys_FIXME + +// #ys_FIXME +// m_update_cnt++; +// ! something to update +// m_update_cnt--; +// +// if (m_update_cnt == 0) + wxGetApp().mainframe->on_config_changed(m_config); } void TabSLAPrint::build() @@ -3298,6 +3369,7 @@ void TabSLAPrint::build() auto optgroup = page->new_optgroup(_(L("Layers"))); optgroup->append_single_option_line("layer_height"); + optgroup->append_single_option_line("faded_layers"); page = add_options_page(_(L("Supports")), "building.png"); optgroup = page->new_optgroup(_(L("Supports"))); @@ -3322,9 +3394,8 @@ void TabSLAPrint::build() optgroup->append_single_option_line("support_max_bridge_length"); optgroup = page->new_optgroup(_(L("Automatic generation"))); - optgroup->append_single_option_line("support_density_at_horizontal"); - optgroup->append_single_option_line("support_density_at_45"); - optgroup->append_single_option_line("support_minimal_z"); + optgroup->append_single_option_line("support_points_density_relative"); + optgroup->append_single_option_line("support_points_minimal_distance"); page = add_options_page(_(L("Pad")), "brick.png"); optgroup = page->new_optgroup(_(L("Pad"))); @@ -3332,7 +3403,13 @@ void TabSLAPrint::build() optgroup->append_single_option_line("pad_wall_thickness"); optgroup->append_single_option_line("pad_wall_height"); optgroup->append_single_option_line("pad_max_merge_distance"); - optgroup->append_single_option_line("pad_edge_radius"); + // TODO: Disabling this parameter for the beta release +// optgroup->append_single_option_line("pad_edge_radius"); + optgroup->append_single_option_line("pad_wall_slope"); + + page = add_options_page(_(L("Advanced")), "wrench.png"); + optgroup = page->new_optgroup(_(L("Slicing"))); + optgroup->append_single_option_line("slice_closing_radius"); page = add_options_page(_(L("Output options")), "page_white_go.png"); optgroup = page->new_optgroup(_(L("Output file"))); @@ -3371,6 +3448,14 @@ void TabSLAPrint::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) return; // #ys_FIXME + +// #ys_FIXME +// m_update_cnt++; +// ! something to update +// m_update_cnt--; +// +// if (m_update_cnt == 0) + wxGetApp().mainframe->on_config_changed(m_config); } } // GUI diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 8273dac78..bf30dc572 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -203,6 +203,8 @@ protected: void set_type(); + int m_em_unit; + public: PresetBundle* m_preset_bundle; bool m_show_btn_incompatible_presets = false; @@ -210,6 +212,11 @@ public: DynamicPrintConfig* m_config; ogStaticText* m_parent_preset_description_line; wxStaticText* m_colored_Label = nullptr; + // Counter for the updating (because of an update() function can have a recursive behavior): + // 1. increase value from the very beginning of an update() function + // 2. decrease value at the end of an update() function + // 3. propagate changed configuration to the Platter when (m_update_cnt == 0) only + int m_update_cnt = 0; public: Tab(wxNotebook* parent, const wxString& title, const char* name); diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 346a9e231..c4b78eb1a 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -12,6 +12,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "GUI.hpp" +#include "GUI_App.hpp" #include "I18N.hpp" #include "ConfigWizard.hpp" @@ -34,7 +35,8 @@ MsgUpdateSlic3r::MsgUpdateSlic3r(const Semver &ver_current, const Semver &ver_on auto *text = new wxStaticText(this, wxID_ANY, _(L("To download, follow the link below."))); const auto link_width = link->GetSize().GetWidth(); - text->Wrap(CONTENT_WIDTH > link_width ? CONTENT_WIDTH : link_width); + const int content_width = CONTENT_WIDTH * wxGetApp().em_unit(); + text->Wrap(content_width > link_width ? content_width : link_width); content_sizer->Add(text); content_sizer->AddSpacer(VERT_SPACING); @@ -75,7 +77,7 @@ MsgUpdateConfig::MsgUpdateConfig(const std::unordered_mapWrap(CONTENT_WIDTH); + text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(text); content_sizer->AddSpacer(VERT_SPACING); @@ -115,16 +117,16 @@ MsgDataIncompatible::MsgDataIncompatible(const std::unordered_mapWrap(CONTENT_WIDTH); + text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(text); auto *text2 = new wxStaticText(this, wxID_ANY, wxString::Format(_(L("This Slic3r PE version: %s")), SLIC3R_VERSION)); - text2->Wrap(CONTENT_WIDTH); + text2->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(text2); content_sizer->AddSpacer(VERT_SPACING); auto *text3 = new wxStaticText(this, wxID_ANY, _(L("Incompatible bundles:"))); - text3->Wrap(CONTENT_WIDTH); + text3->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(text3); content_sizer->AddSpacer(VERT_SPACING); @@ -175,7 +177,7 @@ MsgDataLegacy::MsgDataLegacy() : )), ConfigWizard::name() )); - text->Wrap(CONTENT_WIDTH); + text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(text); content_sizer->AddSpacer(VERT_SPACING); diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 2530f5fea..4c2b2480e 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -3,9 +3,13 @@ #include "WipeTowerDialog.hpp" #include "GUI.hpp" #include "I18N.hpp" +#include "GUI_App.hpp" #include +int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit(); } +int ITEM_WIDTH() { return scale(6); } + RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) : wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) { @@ -65,14 +69,14 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) while (stream >> x >> y) buttons.push_back(std::make_pair(x, y)); - m_chart = new Chart(this, wxRect(10, 10, 480, 360), buttons, ramming_speed_size, 0.25f); + m_chart = new Chart(this, wxRect(scale(1),scale(1),scale(48),scale(36)), buttons, ramming_speed_size, 0.25f, scale(1)); m_chart->SetBackgroundColour(parent->GetBackgroundColour()); // see comment in RammingDialog constructor sizer_chart->Add(m_chart, 0, wxALL, 5); - m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,0.,5.0,3.,0.5); - m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,0,10000,0); - m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,10,200,100); - m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,10,200,100); + m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS,0.,5.0,3.,0.5); + m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS,0,10000,0); + m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS,10,200,100); + m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS,10,200,100); auto gsizer_param = new wxFlexGridSizer(2, 5, 15); gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total ramming time")) + " (" + _(L("s")) + "):")), 0, wxALIGN_CENTER_VERTICAL); @@ -86,7 +90,7 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line spacing")) + " (%):")), 0, wxALIGN_CENTER_VERTICAL); gsizer_param->Add(m_widget_ramming_step_multiplicator); - sizer_param->Add(gsizer_param, 0, wxTOP, 100); + sizer_param->Add(gsizer_param, 0, wxTOP, scale(10)); m_widget_time->SetValue(m_chart->get_time()); m_widget_time->SetDigits(2); @@ -132,7 +136,6 @@ std::string RammingPanel::get_parameters() } -#define ITEM_WIDTH 60 // Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode: WipingDialog::WipingDialog(wxWindow* parent,const std::vector& matrix, const std::vector& extruders) : wxDialog(parent, wxID_ANY, _(L("Wipe tower - Purging volume adjustment")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) @@ -143,7 +146,7 @@ WipingDialog::WipingDialog(wxWindow* parent,const std::vector& matrix, co auto main_sizer = new wxBoxSizer(wxVERTICAL); // set min sizer width according to extruders count - const auto sizer_width = (int)((sqrt(matrix.size()) + 2.8)*ITEM_WIDTH); + const auto sizer_width = (int)((sqrt(matrix.size()) + 2.8)*ITEM_WIDTH()); main_sizer->SetMinSize(wxSize(sizer_width, -1)); main_sizer->Add(m_panel_wiping, 0, wxEXPAND | wxALL, 5); @@ -166,7 +169,10 @@ WipingDialog::WipingDialog(wxWindow* parent,const std::vector& matrix, co // This function allows to "play" with sizers parameters (like align or border) void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_sizer, const wxString& info, const wxString& table_title, int table_lshift/*=0*/) { - sizer->Add(new wxStaticText(page, wxID_ANY, info,wxDefaultPosition,wxSize(0,50)), 0, wxEXPAND | wxLEFT, 15); + wxSize text_size = GetTextExtent(info); + auto info_str = new wxStaticText(page, wxID_ANY, info ,wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER); + info_str->Wrap(int(0.6*text_size.x)); + sizer->Add( info_str, 0, wxALIGN_CENTER_HORIZONTAL | wxEXPAND); auto table_sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(table_sizer, 0, wxALIGN_CENTER | wxCENTER, table_lshift); table_sizer->Add(new wxStaticText(page, wxID_ANY, table_title), 0, wxALIGN_CENTER | wxTOP, 50); @@ -198,7 +204,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con edit_boxes.push_back(std::vector(0)); for (unsigned int j = 0; j < m_number_of_extruders; ++j) { - edit_boxes.back().push_back(new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH, -1))); + edit_boxes.back().push_back(new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1))); if (i == j) edit_boxes[i][j]->Disable(); else @@ -229,8 +235,8 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con gridsizer_simple->Add(new wxStaticText(m_page_simple,wxID_ANY,wxString(_(L("loaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); for (unsigned int i=0;iAdd(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); gridsizer_simple->Add(m_old.back(),0); gridsizer_simple->Add(m_new.back(),0); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index d24db63ea..e83101d22 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -13,6 +13,7 @@ #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" #include "libslic3r/GCode/PreviewData.hpp" +#include "I18N.hpp" using Slic3r::GUI::from_u8; @@ -41,7 +42,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, const std::string& icon, wxEvtHandler* event_handler) { - const wxBitmap& bmp = !icon.empty() ? wxBitmap(from_u8(Slic3r::var(icon)), wxBITMAP_TYPE_PNG) : wxNullBitmap; + const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(icon) : wxNullBitmap; return append_menu_item(menu, id, string, description, cb, bmp, event_handler); } @@ -52,7 +53,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin wxMenuItem* item = new wxMenuItem(menu, id, string, description); if (!icon.empty()) - item->SetBitmap(wxBitmap(from_u8(Slic3r::var(icon)), wxBITMAP_TYPE_PNG)); + item->SetBitmap(create_scaled_bitmap(icon)); item->SetSubMenu(sub_menu); menu->Append(item); @@ -402,11 +403,26 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse) // PrusaObjectDataViewModelNode // ---------------------------------------------------------------------------- +wxBitmap create_scaled_bitmap(const std::string& bmp_name) +{ + const double scale_f = Slic3r::GUI::wxGetApp().em_unit()* 0.1;//GetContentScaleFactor(); + if (scale_f == 1.0) + return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG); +// else if (scale_f == 2.0) // use biger icon +// return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name_X2)), wxBITMAP_TYPE_PNG); + + wxImage img = wxImage(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG); + const int sz_w = int(img.GetWidth()*scale_f); + const int sz_h = int(img.GetHeight()*scale_f); + img.Rescale(sz_w, sz_h, wxIMAGE_QUALITY_BILINEAR); + return wxBitmap(img); +} + void PrusaObjectDataViewModelNode::set_object_action_icon() { - m_action_icon = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("add_object.png")), wxBITMAP_TYPE_PNG); + m_action_icon = create_scaled_bitmap("add_object.png"); } void PrusaObjectDataViewModelNode::set_part_action_icon() { - m_action_icon = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(m_type == itVolume ? "cog.png" : "brick_go.png")), wxBITMAP_TYPE_PNG); + m_action_icon = create_scaled_bitmap(m_type == itVolume ? "cog.png" : "brick_go.png"); } Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; @@ -472,7 +488,7 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int ext wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item, const wxString &name, - const int volume_type, + const Slic3r::ModelVolumeType volume_type, const int extruder/* = 0*/, const bool create_frst_child/* = true*/) { @@ -498,7 +514,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &pa if (insert_position > 0) insert_position++; } - const auto node = new PrusaObjectDataViewModelNode(root, name, *m_volume_bmps[volume_type], extruder_str, root->m_volumes_cnt); + const auto node = new PrusaObjectDataViewModelNode(root, name, *m_volume_bmps[int(volume_type)], extruder_str, root->m_volumes_cnt); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // notify control const wxDataViewItem child((void*)node); @@ -1260,13 +1276,13 @@ void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item, ItemChanged(item); } -void PrusaObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const int type) +void PrusaObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type) { if (!item.IsOk() || GetItemType(item) != itVolume) return; PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); - node->SetBitmap(*m_volume_bmps[type]); + node->SetBitmap(*m_volume_bmps[int(type)]); ItemChanged(item); } @@ -1416,26 +1432,26 @@ PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, m_min_value(minValue), m_max_value(maxValue), m_style(style == wxSL_HORIZONTAL || style == wxSL_VERTICAL ? style: wxSL_HORIZONTAL) { -#ifndef __WXOSX__ // SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX - SetDoubleBuffered(true); +#ifdef __WXOSX__ + is_osx = true; #endif //__WXOSX__ + if (!is_osx) + SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX - m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? Slic3r::GUI::from_u8(Slic3r::var("right_half_circle.png")) : - Slic3r::GUI::from_u8(Slic3r::var("up_half_circle.png")), wxBITMAP_TYPE_PNG); - m_bmp_thumb_lower = wxBitmap(style == wxSL_HORIZONTAL ? Slic3r::GUI::from_u8(Slic3r::var("left_half_circle.png")) : - Slic3r::GUI::from_u8(Slic3r::var("down_half_circle.png")), wxBITMAP_TYPE_PNG); + m_bmp_thumb_higher = wxBitmap(create_scaled_bitmap(style == wxSL_HORIZONTAL ? "right_half_circle.png" : "up_half_circle.png")); + m_bmp_thumb_lower = wxBitmap(create_scaled_bitmap(style == wxSL_HORIZONTAL ? "left_half_circle.png" : "down_half_circle.png")); m_thumb_size = m_bmp_thumb_lower.GetSize(); - m_bmp_add_tick_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_add_on.png")), wxBITMAP_TYPE_PNG); - m_bmp_add_tick_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_add_off.png")), wxBITMAP_TYPE_PNG); - m_bmp_del_tick_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_delete_on.png")), wxBITMAP_TYPE_PNG); - m_bmp_del_tick_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_delete_off.png")), wxBITMAP_TYPE_PNG); + m_bmp_add_tick_on = create_scaled_bitmap("colorchange_add_on.png"); + m_bmp_add_tick_off = create_scaled_bitmap("colorchange_add_off.png"); + m_bmp_del_tick_on = create_scaled_bitmap("colorchange_delete_on.png"); + m_bmp_del_tick_off = create_scaled_bitmap("colorchange_delete_off.png"); m_tick_icon_dim = m_bmp_add_tick_on.GetSize().x; - m_bmp_one_layer_lock_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG); - m_bmp_one_layer_lock_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_lock_off.png")), wxBITMAP_TYPE_PNG); - m_bmp_one_layer_unlock_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_unlock_on.png")), wxBITMAP_TYPE_PNG); - m_bmp_one_layer_unlock_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_unlock_off.png")), wxBITMAP_TYPE_PNG); + m_bmp_one_layer_lock_on = create_scaled_bitmap("one_layer_lock_on.png"); + m_bmp_one_layer_lock_off = create_scaled_bitmap("one_layer_lock_off.png"); + m_bmp_one_layer_unlock_on = create_scaled_bitmap("one_layer_unlock_on.png"); + m_bmp_one_layer_unlock_off = create_scaled_bitmap("one_layer_unlock_off.png"); m_lock_icon_dim = m_bmp_one_layer_lock_on.GetSize().x; m_selection = ssUndef; @@ -1454,7 +1470,7 @@ PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, Bind(wxEVT_RIGHT_UP, &PrusaDoubleSlider::OnRightUp, this); // control's view variables - SLIDER_MARGIN = 4 + (style == wxSL_HORIZONTAL ? m_bmp_thumb_higher.GetWidth() : m_bmp_thumb_higher.GetHeight()); + SLIDER_MARGIN = 4 + Slic3r::GUI::wxGetApp().em_unit();//(style == wxSL_HORIZONTAL ? m_bmp_thumb_higher.GetWidth() : m_bmp_thumb_higher.GetHeight()); DARK_ORANGE_PEN = wxPen(wxColour(253, 84, 2)); ORANGE_PEN = wxPen(wxColour(253, 126, 66)); @@ -1466,6 +1482,9 @@ PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, line_pens = { &DARK_GREY_PEN, &GREY_PEN, &LIGHT_GREY_PEN }; segm_pens = { &DARK_ORANGE_PEN, &ORANGE_PEN, &LIGHT_ORANGE_PEN }; + + const wxFont& font = GetFont(); + m_font = is_osx ? font.Smaller().Smaller() : font.Smaller(); } int PrusaDoubleSlider::GetActiveValue() const @@ -1480,7 +1499,9 @@ wxSize PrusaDoubleSlider::DoGetBestSize() const const wxSize size = wxControl::DoGetBestSize(); if (size.x > 1 && size.y > 1) return size; - const int new_size = is_horizontal() ? 80 : 120; + const int new_size = is_horizontal() ? + (is_osx ? 8 : 6) * Slic3r::GUI::wxGetApp().em_unit() : + (is_osx ? 10 : 8) * Slic3r::GUI::wxGetApp().em_unit(); return wxSize(new_size, new_size); } @@ -1544,7 +1565,7 @@ void PrusaDoubleSlider::draw_scroll_line(wxDC& dc, const int lower_pos, const in wxCoord line_end_y = is_horizontal() ? height*0.5 - 1 : height - SLIDER_MARGIN + 1; wxCoord segm_beg_x = is_horizontal() ? lower_pos : width*0.5 - 1; - wxCoord segm_beg_y = is_horizontal() ? height*0.5 - 1 : lower_pos-1; + wxCoord segm_beg_y = is_horizontal() ? height*0.5 - 1 : lower_pos/*-1*/; wxCoord segm_end_x = is_horizontal() ? higher_pos : width*0.5 - 1; wxCoord segm_end_y = is_horizontal() ? height*0.5 - 1 : higher_pos-1; @@ -1605,8 +1626,11 @@ std::vector PrusaDoubleSlider::GetTicksValues() const std::vector values; if (!m_values.empty()) - for (auto tick : m_ticks) + for (auto tick : m_ticks) { + if (tick > m_values.size()) + break; values.push_back(m_values[tick].second); + } return values; } @@ -1616,6 +1640,8 @@ void PrusaDoubleSlider::SetTicksValues(const std::vector& heights) if (m_values.empty()) return; + const bool was_empty = m_ticks.empty(); + m_ticks.clear(); unsigned int i = 0; for (auto h : heights) { @@ -1625,7 +1651,10 @@ void PrusaDoubleSlider::SetTicksValues(const std::vector& heights) return; m_ticks.insert(i-1); } - + + if (!was_empty && m_ticks.empty()) + // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); } void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos) @@ -1659,9 +1688,7 @@ void PrusaDoubleSlider::render() draw_focus_rect(); wxPaintDC dc(this); - wxFont font = dc.GetFont(); - const wxFont smaller_font = font.Smaller(); - dc.SetFont(smaller_font); + dc.SetFont(m_font); const wxCoord lower_pos = get_position_from_value(m_lower_value); const wxCoord higher_pos = get_position_from_value(m_higher_value); @@ -1713,8 +1740,8 @@ void PrusaDoubleSlider::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, c if (m_selection == selection) { //draw info line dc.SetPen(DARK_ORANGE_PEN); - const wxPoint pt_beg = is_horizontal() ? wxPoint(pos.x, pos.y - m_thumb_size.y) : wxPoint(pos.x - m_thumb_size.x, pos.y - 1); - const wxPoint pt_end = is_horizontal() ? wxPoint(pos.x, pos.y + m_thumb_size.y) : wxPoint(pos.x + m_thumb_size.x, pos.y - 1); + const wxPoint pt_beg = is_horizontal() ? wxPoint(pos.x, pos.y - m_thumb_size.y) : wxPoint(pos.x - m_thumb_size.x, pos.y/* - 1*/); + const wxPoint pt_end = is_horizontal() ? wxPoint(pos.x, pos.y + m_thumb_size.y) : wxPoint(pos.x + m_thumb_size.x, pos.y/* - 1*/); dc.DrawLine(pt_beg, pt_end); //draw action icon @@ -1765,7 +1792,7 @@ void PrusaDoubleSlider::draw_thumb_item(wxDC& dc, const wxPoint& pos, const Sele } else { x_draw = pos.x - int(0.5*m_thumb_size.x); - y_draw = pos.y; + y_draw = pos.y+1; } } else{ @@ -1836,9 +1863,9 @@ void PrusaDoubleSlider::draw_ticks(wxDC& dc) const wxCoord pos = get_position_from_value(tick); is_horizontal() ? dc.DrawLine(pos, mid-14, pos, mid-9) : - dc.DrawLine(mid - 14, pos - 1, mid - 9, pos - 1); + dc.DrawLine(mid - 14, pos/* - 1*/, mid - 9, pos/* - 1*/); is_horizontal() ? dc.DrawLine(pos, mid+14, pos, mid+9) : - dc.DrawLine(mid + 14, pos - 1, mid + 9, pos - 1); + dc.DrawLine(mid + 14, pos/* - 1*/, mid + 9, pos/* - 1*/); } } @@ -2253,10 +2280,11 @@ PrusaLockButton::PrusaLockButton( wxWindow *parent, const wxSize& size /*= wxDefaultSize*/): wxButton(parent, id, wxEmptyString, pos, size, wxBU_EXACTFIT | wxNO_BORDER) { - m_bmp_lock_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG); - m_bmp_lock_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_lock_off.png")), wxBITMAP_TYPE_PNG); - m_bmp_unlock_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_unlock_on.png")), wxBITMAP_TYPE_PNG); - m_bmp_unlock_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_unlock_off.png")), wxBITMAP_TYPE_PNG); + m_bmp_lock_on = create_scaled_bitmap("one_layer_lock_on.png"); + m_bmp_lock_off = create_scaled_bitmap("one_layer_lock_off.png"); + m_bmp_unlock_on = create_scaled_bitmap("one_layer_unlock_on.png"); + m_bmp_unlock_off = create_scaled_bitmap("one_layer_unlock_off.png"); + #ifdef __WXMSW__ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); @@ -2305,15 +2333,18 @@ PrusaModeButton::PrusaModeButton( wxWindow *parent, wxWindowID id, const wxString& mode/* = wxEmptyString*/, const wxBitmap& bmp_on/* = wxNullBitmap*/, - const wxPoint& pos/* = wxDefaultPosition*/, - const wxSize& size/* = wxDefaultSize*/) : - wxButton(parent, id, mode, pos, size, wxBU_EXACTFIT | wxNO_BORDER), + const wxSize& size/* = wxDefaultSize*/, + const wxPoint& pos/* = wxDefaultPosition*/) : + wxButton(parent, id, mode, pos, size, /*wxBU_EXACTFIT | */wxNO_BORDER), m_bmp_on(bmp_on) { #ifdef __WXMSW__ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif // __WXMSW__ - m_bmp_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("mode_off_sq.png")), wxBITMAP_TYPE_PNG); + m_bmp_off = create_scaled_bitmap("mode_off_sq.png"); + + m_tt_focused = wxString::Format(_(L("Switch to the %s mode")), mode); + m_tt_selected = wxString::Format(_(L("Current mode is %s")), mode); SetBitmap(m_bmp_on); @@ -2335,12 +2366,13 @@ void PrusaModeButton::SetState(const bool state) { m_is_selected = state; focus_button(m_is_selected); + SetToolTip(state ? m_tt_selected : m_tt_focused); } void PrusaModeButton::focus_button(const bool focus) { - const wxBitmap& bmp = focus ? m_bmp_on : m_bmp_off; - SetBitmap(bmp); +// const wxBitmap& bmp = focus ? m_bmp_on : m_bmp_off; +// SetBitmap(bmp); const wxFont& new_font = focus ? Slic3r::GUI::wxGetApp().bold_font() : Slic3r::GUI::wxGetApp().small_font(); SetFont(new_font); @@ -2353,20 +2385,25 @@ void PrusaModeButton::focus_button(const bool focus) // PrusaModeSizer // ---------------------------------------------------------------------------- -PrusaModeSizer::PrusaModeSizer(wxWindow *parent) : - wxFlexGridSizer(3, 0, 5) +PrusaModeSizer::PrusaModeSizer(wxWindow *parent, int hgap/* = 10*/) : + wxFlexGridSizer(3, 0, hgap) { SetFlexibleDirection(wxHORIZONTAL); - const wxBitmap bmp_simple_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("mode_simple_sq.png")), wxBITMAP_TYPE_PNG); - const wxBitmap bmp_advanced_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("mode_middle_sq.png")), wxBITMAP_TYPE_PNG); - const wxBitmap bmp_expert_on = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("mode_expert_sq.png")), wxBITMAP_TYPE_PNG); - - mode_btns.reserve(3); + std::vector> buttons = { + {_(L("Simple")), create_scaled_bitmap("mode_simple_sq.png")}, + {_(L("Advanced")), create_scaled_bitmap("mode_middle_sq.png")}, + {_(L("Expert")), create_scaled_bitmap("mode_expert_sq.png")} + }; - mode_btns.push_back(new PrusaModeButton(parent, wxID_ANY, "Simple", bmp_simple_on)); - mode_btns.push_back(new PrusaModeButton(parent, wxID_ANY, "Advanced", bmp_advanced_on)); - mode_btns.push_back(new PrusaModeButton(parent, wxID_ANY, "Expert", bmp_expert_on)); + mode_btns.reserve(3); + for (const auto& button : buttons) { + int x, y; + parent->GetTextExtent(button.first, &x, &y, nullptr, nullptr, &Slic3r::GUI::wxGetApp().bold_font()); + const wxSize size = wxSize(x + button.second.GetWidth() + Slic3r::GUI::wxGetApp().em_unit(), + y + Slic3r::GUI::wxGetApp().em_unit()); + mode_btns.push_back(new PrusaModeButton(parent, wxID_ANY, button.first, button.second, size)); + } for (auto btn : mode_btns) { diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index f124750a1..e0bd5d091 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -16,6 +16,10 @@ #include #include +namespace Slic3r { + enum class ModelVolumeType : int; +}; + wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, const wxBitmap& icon, wxEvtHandler* event_handler = nullptr); wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, @@ -23,6 +27,8 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = ""); +wxBitmap create_scaled_bitmap(const std::string& bmp_name); + class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup { static const unsigned int DefaultWidth; @@ -446,7 +452,7 @@ public: wxDataViewItem Add(const wxString &name, const int extruder); wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item, const wxString &name, - const int volume_type, + const Slic3r::ModelVolumeType volume_type, const int extruder = 0, const bool create_frst_child = true); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); @@ -514,7 +520,7 @@ public: void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector& categories); void SetVolumeBitmaps(const std::vector& volume_bmps) { m_volume_bmps = volume_bmps; } - void SetVolumeType(const wxDataViewItem &item, const int type); + void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type); void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } }; @@ -785,6 +791,8 @@ protected: double get_double_value(const SelectedSlider& selection); private: + bool is_osx { false }; + wxFont m_font; int m_min_value; int m_max_value; int m_lower_value; @@ -882,8 +890,8 @@ public: wxWindowID id, const wxString& mode = wxEmptyString, const wxBitmap& bmp_on = wxNullBitmap, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize); + const wxSize& size = wxDefaultSize, + const wxPoint& pos = wxDefaultPosition); ~PrusaModeButton() {} void OnButton(wxCommandEvent& event); @@ -900,6 +908,8 @@ private: wxBitmap m_bmp_on; wxBitmap m_bmp_off; + wxString m_tt_selected; + wxString m_tt_focused; }; @@ -911,7 +921,7 @@ private: class PrusaModeSizer : public wxFlexGridSizer { public: - PrusaModeSizer( wxWindow *parent); + PrusaModeSizer( wxWindow *parent, int hgap = 10); ~PrusaModeSizer() {} void SetMode(const /*ConfigOptionMode*/int mode); diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index d9db07a45..02bbc087e 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -244,7 +244,7 @@ void Http::priv::http_perform() ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, static_cast(this)); #endif - ::curl_easy_setopt(curl, CURLOPT_VERBOSE, get_logging_level() >= 4); + ::curl_easy_setopt(curl, CURLOPT_VERBOSE, get_logging_level() >= 5); if (headerlist != nullptr) { ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index a22d463fb..6924f86de 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include "libslic3r/libslic3r.h" @@ -90,9 +89,25 @@ struct Updates std::vector updates; }; +static Semver get_slic3r_version() +{ + auto res = Semver::parse(SLIC3R_VERSION); + + if (! res) { + const char *error = "Could not parse Slic3r version string: " SLIC3R_VERSION; + BOOST_LOG_TRIVIAL(error) << error; + throw std::runtime_error(error); + } + + return *res; +} + +wxDEFINE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); + struct PresetUpdater::priv { + const Semver ver_slic3r; std::vector index_db; bool enabled_version_check; @@ -122,12 +137,13 @@ struct PresetUpdater::priv static void copy_file(const fs::path &from, const fs::path &to); }; -PresetUpdater::priv::priv() : - had_config_update(false), - cache_path(fs::path(Slic3r::data_dir()) / "cache"), - rsrc_path(fs::path(resources_dir()) / "profiles"), - vendor_path(fs::path(Slic3r::data_dir()) / "vendor"), - cancel(false) +PresetUpdater::priv::priv() + : ver_slic3r(get_slic3r_version()) + , had_config_update(false) + , cache_path(fs::path(Slic3r::data_dir()) / "cache") + , rsrc_path(fs::path(resources_dir()) / "profiles") + , vendor_path(fs::path(Slic3r::data_dir()) / "vendor") + , cancel(false) { set_download_prefs(GUI::wxGetApp().app_config); check_install_indices(); @@ -209,11 +225,10 @@ void PresetUpdater::priv::sync_version() const .on_complete([&](std::string body, unsigned /* http_status */) { boost::trim(body); BOOST_LOG_TRIVIAL(info) << boost::format("Got Slic3rPE online version: `%1%`. Sending to GUI thread...") % body; -// wxCommandEvent* evt = new wxCommandEvent(version_online_event); -// evt->SetString(body); -// GUI::get_app()->QueueEvent(evt); - GUI::wxGetApp().app_config->set("version_online", body); - GUI::wxGetApp().app_config->save(); + + wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); + evt->SetString(GUI::from_u8(body)); + GUI::wxGetApp().QueueEvent(evt); }) .perform_sync(); } @@ -260,7 +275,7 @@ void PresetUpdater::priv::sync_config(const std::set vendors) continue; } if (new_index.version() < index.version()) { - BOOST_LOG_TRIVIAL(error) << boost::format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.") % idx_path_temp % vendor.name; + BOOST_LOG_TRIVIAL(warning) << boost::format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.") % idx_path_temp % vendor.name; continue; } Slic3r::rename_file(idx_path_temp, idx_path); @@ -275,6 +290,7 @@ void PresetUpdater::priv::sync_config(const std::set vendors) BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % vendor.name; continue; } + const auto recommended = recommended_it->config_version; BOOST_LOG_TRIVIAL(debug) << boost::format("Got index for vendor: %1%: current version: %2%, recommended version: %3%") @@ -337,13 +353,6 @@ Updates PresetUpdater::priv::get_config_updates() const // Perform a basic load and check the version const auto vp = VendorProfile::from_ini(bundle_path, false); - const auto ver_current = idx.find(vp.config_version); - if (ver_current == idx.end()) { - auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str(); - BOOST_LOG_TRIVIAL(error) << message; - throw std::runtime_error(message); - } - // Getting a recommended version from the latest index, wich may have been downloaded // from the internet, or installed / updated from the installation resources. const auto recommended = idx.recommended(); @@ -351,15 +360,24 @@ Updates PresetUpdater::priv::get_config_updates() const BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % idx.vendor(); } - BOOST_LOG_TRIVIAL(debug) << boost::format("Vendor: %1%, version installed: %2%, version cached: %3%") + const auto ver_current = idx.find(vp.config_version); + const bool ver_current_found = ver_current != idx.end(); + if (! ver_current_found) { + auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str(); + BOOST_LOG_TRIVIAL(error) << message; + GUI::show_error(nullptr, GUI::from_u8(message)); + } + + BOOST_LOG_TRIVIAL(debug) << boost::format("Vendor: %1%, version installed: %2%%3%, version cached: %4%") % vp.name - % ver_current->config_version.to_string() + % vp.config_version.to_string() + % (ver_current_found ? "" : " (not found in index!)") % recommended->config_version.to_string(); - if (! ver_current->is_current_slic3r_supported()) { + if (ver_current_found && !ver_current->is_current_slic3r_supported()) { BOOST_LOG_TRIVIAL(warning) << "Current Slic3r incompatible with installed bundle: " << bundle_path.string(); updates.incompats.emplace_back(std::move(bundle_path), *ver_current); - } else if (recommended->config_version > ver_current->config_version) { + } else if (recommended->config_version > vp.config_version) { // Config bundle update situation // Check if the update is already present in a snapshot @@ -528,18 +546,14 @@ void PresetUpdater::slic3r_update_notify() } auto* app_config = GUI::wxGetApp().app_config; - const auto ver_slic3r = Semver::parse(SLIC3R_VERSION); const auto ver_online_str = app_config->get("version_online"); const auto ver_online = Semver::parse(ver_online_str); const auto ver_online_seen = Semver::parse(app_config->get("version_online_seen")); - if (! ver_slic3r) { - throw std::runtime_error("Could not parse Slic3r version string: " SLIC3R_VERSION); - } if (ver_online) { // Only display the notification if the version available online is newer AND if we haven't seen it before - if (*ver_online > *ver_slic3r && (! ver_online_seen || *ver_online_seen < *ver_online)) { - GUI::MsgUpdateSlic3r notification(*ver_slic3r, *ver_online); + if (*ver_online > p->ver_slic3r && (! ver_online_seen || *ver_online_seen < *ver_online)) { + GUI::MsgUpdateSlic3r notification(p->ver_slic3r, *ver_online); notification.ShowModal(); if (notification.disable_version_check()) { app_config->set("version_check", "0"); diff --git a/src/slic3r/Utils/PresetUpdater.hpp b/src/slic3r/Utils/PresetUpdater.hpp index 451e8b2cf..4b20c18e3 100644 --- a/src/slic3r/Utils/PresetUpdater.hpp +++ b/src/slic3r/Utils/PresetUpdater.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace Slic3r { @@ -37,6 +39,8 @@ private: std::unique_ptr p; }; +wxDECLARE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); + } #endif diff --git a/version.inc b/version.inc index aa8470bd4..b9d77933a 100644 --- a/version.inc +++ b/version.inc @@ -2,7 +2,7 @@ # (the version numbers are generated by the build script from the git current label) set(SLIC3R_FORK_NAME "Slic3r++") -set(SLIC3R_VERSION "1.42.0-alpha5.0") +set(SLIC3R_VERSION "1.42.0-alpha7.0") set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}") set(SLIC3R_RC_VERSION "1,42,0,0") diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 8f1d88c74..a1c8890ef 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -258,17 +258,17 @@ ModelMaterial::attributes() bool modifier() %code%{ RETVAL = THIS->is_modifier(); %}; void set_modifier(bool modifier) - %code%{ THIS->set_type(modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART); %}; + %code%{ THIS->set_type(modifier ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART); %}; bool model_part() %code%{ RETVAL = THIS->is_model_part(); %}; bool support_enforcer() %code%{ RETVAL = THIS->is_support_enforcer(); %}; void set_support_enforcer() - %code%{ THIS->set_type(ModelVolume::SUPPORT_ENFORCER); %}; + %code%{ THIS->set_type(ModelVolumeType::SUPPORT_ENFORCER); %}; bool support_blocker() %code%{ RETVAL = THIS->is_support_blocker(); %}; void set_support_blocker() - %code%{ THIS->set_type(ModelVolume::SUPPORT_BLOCKER); %}; + %code%{ THIS->set_type(ModelVolumeType::SUPPORT_BLOCKER); %}; size_t split(unsigned int max_extruders); }; diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index 95f2f7d52..edfb4a198 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -185,7 +185,7 @@ TriangleMesh::slice(z) std::vector layers; TriangleMeshSlicer mslicer(THIS); - mslicer.slice(z_f, &layers, [](){}); + mslicer.slice(z_f, 0.049f, &layers, [](){}); AV* layers_av = newAV(); size_t len = layers.size();