diff --git a/cmake/modules/FindFlann.cmake b/cmake/modules/FindFlann.cmake deleted file mode 100644 index 98674d230..000000000 --- a/cmake/modules/FindFlann.cmake +++ /dev/null @@ -1,28 +0,0 @@ -############################################################################### -# Find Flann -# -# This sets the following variables: -# FLANN_FOUND - True if FLANN was found. -# FLANN_INCLUDE_DIRS - Directories containing the FLANN include files. -# FLANN_LIBRARIES - Libraries needed to use FLANN. -# FLANN_DEFINITIONS - Compiler flags for FLANN. - -find_package(PkgConfig) -pkg_check_modules(PC_FLANN flann) -set(FLANN_DEFINITIONS ${PC_FLANN_CFLAGS_OTHER}) - -find_path(FLANN_INCLUDE_DIR flann/flann.hpp - HINTS ${PC_FLANN_INCLUDEDIR} ${PC_FLANN_INCLUDE_DIRS}) - -find_library(FLANN_LIBRARY flann_cpp - HINTS ${PC_FLANN_LIBDIR} ${PC_FLANN_LIBRARY_DIRS}) - -set(FLANN_INCLUDE_DIRS ${FLANN_INCLUDE_DIR}) -set(FLANN_LIBRARIES ${FLANN_LIBRARY}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Flann DEFAULT_MSG - FLANN_LIBRARY FLANN_INCLUDE_DIR) - -mark_as_advanced(FLANN_LIBRARY FLANN_INCLUDE_DIR) - diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 5a8bf3f8a..c4c7224fb 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -296,29 +296,42 @@ sub new { } }); - 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::_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->{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->{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; - if (($preview != $self->{preview3D}) && ($preview != $self->{canvas3D})) { + 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 ($preview == $self->{preview3D}) { - $self->{preview3D}->reload_print; + } 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) - Slic3r::GUI::_3DScene::set_as_dirty($self->{preview3D}->canvas); + $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; @@ -461,7 +474,8 @@ sub new { $_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self)) for grep defined($_), - $self, $self->{canvas3D}, $self->{preview3D}, $self->{list}; + $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 { @@ -488,9 +502,10 @@ sub new { Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape); Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D}); } - if ($self->{preview3D}) { - Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape); - } + $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; { @@ -1005,7 +1020,8 @@ sub remove { $self->stop_background_process; # Prevent toolpaths preview from rendering while we modify the Print object - $self->{preview3D}->enabled(0) if $self->{preview3D}; + $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) { @@ -1030,7 +1046,8 @@ sub reset { $self->stop_background_process; # Prevent toolpaths preview from rendering while we modify the Print object - $self->{preview3D}->enabled(0) if $self->{preview3D}; + $self->{preview_iface}->set_enabled(0) if $self->{preview_iface}; +# $self->{preview3D}->enabled(0) if $self->{preview3D}; @{$self->{objects}} = (); $self->{model}->clear_objects; @@ -1391,7 +1408,8 @@ sub async_apply_config { # 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->{preview3D}->reload_print if $self->{preview3D}; + $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; @@ -1426,7 +1444,8 @@ sub start_background_process { sub stop_background_process { my ($self) = @_; $self->{background_slicing_process}->stop(); - $self->{preview3D}->reload_print if $self->{preview3D}; + $self->{preview_iface}->reload_print if $self->{preview_iface}; +# $self->{preview3D}->reload_print if $self->{preview3D}; } # Called by the "Slice now" button, which is visible only if the background processing is disabled. @@ -1532,7 +1551,8 @@ sub export_gcode { # This message should be called by the background process synchronously. sub on_update_print_preview { my ($self) = @_; - $self->{preview3D}->reload_print if $self->{preview3D}; + $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; @@ -1613,7 +1633,8 @@ sub on_process_completed { $self->object_list_changed; # refresh preview - $self->{preview3D}->reload_print if $self->{preview3D}; + $self->{preview_iface}->reload_print if $self->{preview_iface}; +# $self->{preview3D}->reload_print if $self->{preview3D}; } # Fill in the "Sliced info" box with the result of the G-code generator. @@ -1881,8 +1902,10 @@ sub update { my $selections = $self->collect_selections; Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0); - $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D}; - $self->{preview3D}->reload_print if $self->{preview3D}; + $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; } @@ -1958,7 +1981,8 @@ sub on_config_change { 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}; - Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D}; + $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; @@ -1993,13 +2017,15 @@ sub on_config_change { } elsif ($opt_key eq 'extruder_colour') { $update_scheduled = 1; my $extruder_colors = $config->get('extruder_colour'); - $self->{preview3D}->set_number_extruders(scalar(@{$extruder_colors})); + $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}; - Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D}; + $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; } } @@ -2451,11 +2477,14 @@ sub select_view { 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')) { - Slic3r::GUI::_3DScene::select_view($self->{preview3D}->canvas, $direction); - Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); + $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); - Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); + $self->{preview_iface}->set_viewport_from_scene($self->{canvas3D}); +# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); } } diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 7c3871251..c3c59fc30 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -7,10 +7,6 @@ #include #include -#include -#include -#include - #include #include "Rasterizer/Rasterizer.hpp" @@ -32,7 +28,7 @@ enum class FilePrinterFormat { * different implementations of this class template for each supported format. * */ -template +template class FilePrinter { public: @@ -73,10 +69,33 @@ public: void saveLayer(unsigned lyr, const std::string& path); }; +template struct VeryFalse { static const bool value = false; }; + +// This has to be explicitly implemented in the gui layer or a default zlib +// based implementation is needed. +template class Zipper { +public: + + Zipper(const std::string& /*zipfile_path*/) { + static_assert(VeryFalse::value, + "No zipper implementation provided!"); + } + + void next_entry(const std::string& /*fname*/) {} + + std::string get_name() { return ""; } + + template Zipper& operator<<(const T& /*arg*/) { + return *this; + } + + void close() {} +}; + // Implementation for PNG raster output // Be aware that if a large number of layers are allocated, it can very well // exhaust the available memory especially on 32 bit platform. -template<> class FilePrinter { +template class FilePrinter { struct Layer { Raster first; @@ -148,7 +167,7 @@ public: pxdim_(m.pxdim_) {} inline void layers(unsigned cnt) { if(cnt > 0) layers_rst_.resize(cnt); } - inline unsigned layers() const { return layers_rst_.size(); } + inline unsigned layers() const { return unsigned(layers_rst_.size()); } void printConfig(const Print& printconf) { print_ = &printconf; } @@ -183,38 +202,63 @@ public: } inline void save(const std::string& path) { + try { + Zipper zipper(path); - wxFileName filepath(path); + std::string project = zipper.get_name(); - wxFFileOutputStream zipfile(path); + zipper.next_entry(project); + zipper << createIniContent(project); - std::string project = filepath.GetName().ToStdString(); + for(unsigned i = 0; i < layers_rst_.size(); i++) { + if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { + char lyrnum[6]; + std::sprintf(lyrnum, "%.5d", i); + auto zfilename = project + lyrnum + ".png"; + zipper.next_entry(zfilename); + zipper << layers_rst_[i].second.rdbuf(); + layers_rst_[i].second.str(""); + } + } - if(!zipfile.IsOk()) { + zipper.close(); + } catch(std::exception&) { BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers! " << path; return; } - wxZipOutputStream zipstream(zipfile); - wxStdOutputStream pngstream(zipstream); +// wxFileName filepath(path); - zipstream.PutNextEntry("config.ini"); - pngstream << createIniContent(project); +// wxFFileOutputStream zipfile(path); - for(unsigned i = 0; i < layers_rst_.size(); i++) { - if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { - char lyrnum[6]; - std::sprintf(lyrnum, "%.5d", i); - auto zfilename = project + lyrnum + ".png"; - zipstream.PutNextEntry(zfilename); - pngstream << layers_rst_[i].second.rdbuf(); - layers_rst_[i].second.str(""); - } - } +// std::string project = filepath.GetName().ToStdString(); - zipstream.Close(); - zipfile.Close(); +// if(!zipfile.IsOk()) { +// BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers! " +// << path; +// return; +// } + +// wxZipOutputStream zipstream(zipfile); +// wxStdOutputStream pngstream(zipstream); + +// zipstream.PutNextEntry("config.ini"); +// pngstream << createIniContent(project); + +// for(unsigned i = 0; i < layers_rst_.size(); i++) { +// if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { +// char lyrnum[6]; +// std::sprintf(lyrnum, "%.5d", i); +// auto zfilename = project + lyrnum + ".png"; +// zipstream.PutNextEntry(zfilename); +// pngstream << layers_rst_[i].second.rdbuf(); +// layers_rst_[i].second.str(""); +// } +// } + +// zipstream.Close(); +// zipfile.Close(); } void saveLayer(unsigned lyr, const std::string& path) { @@ -243,7 +287,7 @@ inline coord_t py(const Point& p) { return p(1); } inline coordf_t px(const Vec2d& p) { return p(0); } inline coordf_t py(const Vec2d& p) { return p(1); } -template +template void print_to(Print& print, std::string dirpath, double width_mm, @@ -261,7 +305,9 @@ void print_to(Print& print, auto& objects = print.objects(); // Merge the sliced layers with the support layers - std::for_each(objects.cbegin(), objects.cend(), [&layers](const PrintObject *o) { + std::for_each(objects.cbegin(), objects.cend(), + [&layers](const PrintObject *o) + { for(const auto l : o->layers()) { auto& lyrs = layers[static_cast(scale_(l->print_z))]; lyrs.push_back(l); @@ -288,8 +334,8 @@ void print_to(Print& print, auto cy = scale_(height_mm)/2 - (py(print_bb.center()) - py(print_bb.min)); // Create the actual printer, forward any additional arguments to it. - FilePrinter printer(width_mm, height_mm, - std::forward(args)...); + FilePrinter printer(width_mm, height_mm, + std::forward(args)...); printer.printConfig(print); @@ -303,14 +349,11 @@ void print_to(Print& print, keys.reserve(layers.size()); for(auto& e : layers) keys.push_back(e.first); - //FIXME - int initstatus = //print.progressindicator? print.progressindicator->state() : - 0; - print.set_status(initstatus, jobdesc); + print.set_status(0, jobdesc); // Method that prints one layer auto process_layer = [&layers, &keys, &printer, &st_prev, &m, - &jobdesc, print_bb, dir, cx, cy, &print, initstatus] + &jobdesc, print_bb, dir, cx, cy, &print] (unsigned layer_id) { LayerPtrs lrange = layers[keys[layer_id]]; @@ -354,7 +397,7 @@ void print_to(Print& print, auto st = static_cast(layer_id*80.0/layers.size()); m.lock(); if( st - st_prev > 10) { - print.set_status(initstatus + st, jobdesc); + print.set_status(st, jobdesc); st_prev = st; } m.unlock(); @@ -373,9 +416,9 @@ void print_to(Print& print, // print.set_status(100, jobdesc); // Save the print into the file system. - print.set_status(initstatus + 90, "Writing layers to disk"); + print.set_status(90, "Writing layers to disk"); printer.save(dir); - print.set_status(initstatus + 100, "Writing layers completed"); + print.set_status(100, "Writing layers completed"); } } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 2bcf597e6..bd1a9f3fb 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -2618,7 +2618,10 @@ void modulate_extrusion_by_overlapping_layers( (fragment_end.is_start ? &polyline.points.front() : &polyline.points.back()); } private: - ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) {} + ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) { + return *this; + } + const std::vector &m_path_fragments; }; const coord_t search_radius = 7; diff --git a/src/slic3r/AppController.cpp b/src/slic3r/AppController.cpp index 4a36b5d7f..6728c6c00 100644 --- a/src/slic3r/AppController.cpp +++ b/src/slic3r/AppController.cpp @@ -11,12 +11,17 @@ #include #include -#include #include #include +#include +#include #include #include +#include +#include +#include + namespace Slic3r { class AppControllerBoilerplate::PriData { @@ -43,6 +48,15 @@ namespace GUI { PresetBundle* get_preset_bundle(); } +static const PrintObjectStep STEP_SLICE = posSlice; +static const PrintObjectStep STEP_PERIMETERS = posPerimeters; +static const PrintObjectStep STEP_PREPARE_INFILL = posPrepareInfill; +static const PrintObjectStep STEP_INFILL = posInfill; +static const PrintObjectStep STEP_SUPPORTMATERIAL = posSupportMaterial; +static const PrintStep STEP_SKIRT = psSkirt; +static const PrintStep STEP_BRIM = psBrim; +static const PrintStep STEP_WIPE_TOWER = psWipeTower; + AppControllerBoilerplate::ProgresIndicatorPtr AppControllerBoilerplate::global_progress_indicator() { ProgresIndicatorPtr ret; @@ -62,6 +76,376 @@ void AppControllerBoilerplate::global_progress_indicator( pri_data_->m.unlock(); } +//void PrintController::make_skirt() +//{ +// assert(print_ != nullptr); + +// // prerequisites +// for(auto obj : print_->objects) make_perimeters(obj); +// for(auto obj : print_->objects) infill(obj); +// for(auto obj : print_->objects) gen_support_material(obj); + +// if(!print_->state.is_done(STEP_SKIRT)) { +// print_->state.set_started(STEP_SKIRT); +// print_->skirt.clear(); +// if(print_->has_skirt()) print_->_make_skirt(); + +// print_->state.set_done(STEP_SKIRT); +// } +//} + +//void PrintController::make_brim() +//{ +// assert(print_ != nullptr); + +// // prerequisites +// for(auto obj : print_->objects) make_perimeters(obj); +// for(auto obj : print_->objects) infill(obj); +// for(auto obj : print_->objects) gen_support_material(obj); +// make_skirt(); + +// if(!print_->state.is_done(STEP_BRIM)) { +// print_->state.set_started(STEP_BRIM); + +// // since this method must be idempotent, we clear brim paths *before* +// // checking whether we need to generate them +// print_->brim.clear(); + +// if(print_->config.brim_width > 0) print_->_make_brim(); + +// print_->state.set_done(STEP_BRIM); +// } +//} + +//void PrintController::make_wipe_tower() +//{ +// assert(print_ != nullptr); + +// // prerequisites +// for(auto obj : print_->objects) make_perimeters(obj); +// for(auto obj : print_->objects) infill(obj); +// for(auto obj : print_->objects) gen_support_material(obj); +// make_skirt(); +// make_brim(); + +// if(!print_->state.is_done(STEP_WIPE_TOWER)) { +// print_->state.set_started(STEP_WIPE_TOWER); + +// // since this method must be idempotent, we clear brim paths *before* +// // checking whether we need to generate them +// print_->brim.clear(); + +// if(print_->has_wipe_tower()) print_->_make_wipe_tower(); + +// print_->state.set_done(STEP_WIPE_TOWER); +// } +//} + +//void PrintController::slice(PrintObject *pobj) +//{ +// assert(pobj != nullptr && print_ != nullptr); + +// if(pobj->state.is_done(STEP_SLICE)) return; + +// pobj->state.set_started(STEP_SLICE); + +// pobj->_slice(); + +// auto msg = pobj->_fix_slicing_errors(); +// if(!msg.empty()) report_issue(IssueType::WARN, msg); + +// // simplify slices if required +// if (print_->config.resolution) +// pobj->_simplify_slices(scale_(print_->config.resolution)); + + +// if(pobj->layers.empty()) +// report_issue(IssueType::ERR, +// L("No layers were detected. You might want to repair your " +// "STL file(s) or check their size or thickness and retry") +// ); + +// pobj->state.set_done(STEP_SLICE); +//} + +//void PrintController::make_perimeters(PrintObject *pobj) +//{ +// assert(pobj != nullptr); + +// slice(pobj); + +// if (!pobj->state.is_done(STEP_PERIMETERS)) { +// pobj->_make_perimeters(); +// } +//} + +//void PrintController::infill(PrintObject *pobj) +//{ +// assert(pobj != nullptr); + +// make_perimeters(pobj); + +// if (!pobj->state.is_done(STEP_PREPARE_INFILL)) { +// pobj->state.set_started(STEP_PREPARE_INFILL); + +// pobj->_prepare_infill(); + +// pobj->state.set_done(STEP_PREPARE_INFILL); +// } + +// pobj->_infill(); +//} + +//void PrintController::gen_support_material(PrintObject *pobj) +//{ +// assert(pobj != nullptr); + +// // prerequisites +// slice(pobj); + +// if(!pobj->state.is_done(STEP_SUPPORTMATERIAL)) { +// pobj->state.set_started(STEP_SUPPORTMATERIAL); + +// pobj->clear_support_layers(); + +// if((pobj->config.support_material || pobj->config.raft_layers > 0) +// && pobj->layers.size() > 1) { +// pobj->_generate_support_material(); +// } + +// pobj->state.set_done(STEP_SUPPORTMATERIAL); +// } +//} + +PrintController::PngExportData +PrintController::query_png_export_data(const DynamicPrintConfig& conf) +{ + PngExportData ret; + + auto zippath = query_destination_path("Output zip file", "*.zip", "out"); + + ret.zippath = zippath; + + ret.width_mm = conf.opt_float("display_width"); + ret.height_mm = conf.opt_float("display_height"); + + ret.width_px = conf.opt_int("display_pixels_x"); + ret.height_px = conf.opt_int("display_pixels_y"); + + auto opt_corr = conf.opt("printer_correction"); + + if(opt_corr) { + ret.corr_x = opt_corr->values[0]; + ret.corr_y = opt_corr->values[1]; + ret.corr_z = opt_corr->values[2]; + } + + ret.exp_time_first_s = conf.opt_float("initial_exposure_time"); + ret.exp_time_s = conf.opt_float("exposure_time"); + + return ret; +} + +void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri) +{ + auto st = pri->state(); + + Slic3r::trace(3, "Starting the slicing process."); + + pri->update(st+20, L("Generating perimeters")); +// for(auto obj : print_->objects) make_perimeters(obj); + + pri->update(st+60, L("Infilling layers")); +// for(auto obj : print_->objects) infill(obj); + + pri->update(st+70, L("Generating support material")); +// for(auto obj : print_->objects) gen_support_material(obj); + +// pri->message_fmt(L("Weight: %.1fg, Cost: %.1f"), +// print_->total_weight, print_->total_cost); + pri->state(st+85); + + + pri->update(st+88, L("Generating skirt")); + make_skirt(); + + + pri->update(st+90, L("Generating brim")); + make_brim(); + + pri->update(st+95, L("Generating wipe tower")); + make_wipe_tower(); + + pri->update(st+100, L("Done")); + + // time to make some statistics.. + + Slic3r::trace(3, L("Slicing process finished.")); +} + +void PrintController::slice() +{ + auto pri = global_progress_indicator(); + if(!pri) pri = create_progress_indicator(100, L("Slicing")); + slice(pri); +} + +struct wxZipper {}; + +template<> class Zipper { + wxFileName m_fpath; + wxFFileOutputStream m_zipfile; + wxZipOutputStream m_zipstream; + wxStdOutputStream m_pngstream; +public: + + Zipper(const std::string& zipfile_path): + m_fpath(zipfile_path), + m_zipfile(zipfile_path), + m_zipstream(m_zipfile), + m_pngstream(m_zipstream) + { + if(!m_zipfile.IsOk()) + throw std::runtime_error(L("Cannot create zip file.")); + } + + void next_entry(const std::string& fname) { + m_zipstream.PutNextEntry(fname); + } + + std::string get_name() { + return m_fpath.GetName().ToStdString(); + } + + template Zipper& operator<<(const T& arg) { + m_pngstream << arg; return *this; + } + + void close() { + m_zipstream.Close(); + m_zipfile.Close(); + } +}; + +void PrintController::slice_to_png() +{ + using Pointf3 = Vec3d; + + auto presetbundle = GUI::get_preset_bundle(); + + assert(presetbundle); + + auto pt = presetbundle->printers.get_selected_preset().printer_technology(); + if(pt != ptSLA) { + report_issue(IssueType::ERR, L("Printer technology is not SLA!"), + L("Error")); + return; + } + + auto conf = presetbundle->full_config(); + conf.validate(); + + auto exd = query_png_export_data(conf); + if(exd.zippath.empty()) return; + + Print *print = print_; + + try { + print->apply_config(conf); + print->validate(); + } catch(std::exception& e) { + report_issue(IssueType::ERR, e.what(), "Error"); + return; + } + + // TODO: copy the model and work with the copy only + bool correction = false; + if(exd.corr_x != 1.0 || exd.corr_y != 1.0 || exd.corr_z != 1.0) { + correction = true; +// print->invalidate_all_steps(); + +// for(auto po : print->objects) { +// po->model_object()->scale( +// Pointf3(exd.corr_x, exd.corr_y, exd.corr_z) +// ); +// po->model_object()->invalidate_bounding_box(); +// po->reload_model_instances(); +// po->invalidate_all_steps(); +// } + } + + // Turn back the correction scaling on the model. + auto scale_back = [this, print, correction, exd]() { + if(correction) { // scale the model back +// print->invalidate_all_steps(); +// for(auto po : print->objects) { +// po->model_object()->scale( +// Pointf3(1.0/exd.corr_x, 1.0/exd.corr_y, 1.0/exd.corr_z) +// ); +// po->model_object()->invalidate_bounding_box(); +// po->reload_model_instances(); +// po->invalidate_all_steps(); +// } + } + }; + + auto print_bb = print->bounding_box(); + Vec2d punsc = unscale(print_bb.size()); + + // If the print does not fit into the print area we should cry about it. + if(px(punsc) > exd.width_mm || py(punsc) > exd.height_mm) { + std::stringstream ss; + + ss << L("Print will not fit and will be truncated!") << "\n" + << L("Width needed: ") << px(punsc) << " mm\n" + << L("Height needed: ") << py(punsc) << " mm\n"; + + if(!report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) { + scale_back(); + return; + } + } + + auto pri = create_progress_indicator( + 200, L("Slicing to zipped png files...")); + + pri->on_cancel([&print](){ print->cancel(); }); + + try { + pri->update(0, L("Slicing...")); + slice(pri); + } catch (std::exception& e) { + report_issue(IssueType::ERR, e.what(), L("Exception occurred")); + scale_back(); + if(print->canceled()) print->restart(); + return; + } + + auto initstate = unsigned(pri->state()); + print->set_status_callback([pri, initstate](int st, const std::string& msg) + { + pri->update(initstate + unsigned(st), msg); + }); + + try { + print_to( *print, exd.zippath, + exd.width_mm, exd.height_mm, + exd.width_px, exd.height_px, + exd.exp_time_s, exd.exp_time_first_s); + + } catch (std::exception& e) { + report_issue(IssueType::ERR, e.what(), L("Exception occurred")); + } + + scale_back(); + if(print->canceled()) print->restart(); +} + +const PrintConfig &PrintController::config() const +{ + return print_->config(); +} + void ProgressIndicator::message_fmt( const std::string &fmtstr, ...) { std::stringstream ss; diff --git a/src/slic3r/AppController.hpp b/src/slic3r/AppController.hpp index 71472835e..88d1f0eca 100644 --- a/src/slic3r/AppController.hpp +++ b/src/slic3r/AppController.hpp @@ -165,12 +165,49 @@ protected: ProgresIndicatorPtr global_progressind_; }; -#if 0 /** * @brief Implementation of the printing logic. */ class PrintController: public AppControllerBoilerplate { Print *print_ = nullptr; + std::function rempools_; +protected: + + void make_skirt() {} + void make_brim() {} + void make_wipe_tower() {} + + void make_perimeters(PrintObject *pobj) {} + void infill(PrintObject *pobj) {} + void gen_support_material(PrintObject *pobj) {} + + // Data structure with the png export input data + struct PngExportData { + std::string zippath; // output zip file + unsigned long width_px = 1440; // resolution - rows + unsigned long height_px = 2560; // resolution columns + double width_mm = 68.0, height_mm = 120.0; // dimensions in mm + double exp_time_first_s = 35.0; // first exposure time + double exp_time_s = 8.0; // global exposure time + double corr_x = 1.0; // offsetting in x + double corr_y = 1.0; // offsetting in y + double corr_z = 1.0; // offsetting in y + }; + + // Should display a dialog with the input fields for printing to png + PngExportData query_png_export_data(const DynamicPrintConfig&); + + // The previous export data, to pre-populate the dialog + PngExportData prev_expdata_; + + /** + * @brief Slice one pront object. + * @param pobj The print object. + */ + void slice(PrintObject *pobj); + + void slice(ProgresIndicatorPtr pri); + public: // Must be public for perl to use it @@ -185,24 +222,18 @@ public: return PrintController::Ptr( new PrintController(print) ); } - void slice() {} - void slice_to_png() {} + /** + * @brief Slice the loaded print scene. + */ + void slice(); + + /** + * @brief Slice the print into zipped png files. + */ + void slice_to_png(); const PrintConfig& config() const; }; -#else -class PrintController: public AppControllerBoilerplate { -public: - using Ptr = std::unique_ptr; - explicit inline PrintController(Print *print){} - inline static Ptr create(Print *print) { - return PrintController::Ptr( new PrintController(print) ); - } - void slice() {} - void slice_to_png() {} - const PrintConfig& config() const { static PrintConfig cfg; return cfg; } -}; -#endif /** * @brief Top level controller. diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 24d459921..e5ed917b3 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -991,6 +991,12 @@ wxString from_u8(const std::string &str) return wxString::FromUTF8(str.c_str()); } +std::string into_u8(const wxString &str) +{ + auto buffer_utf8 = str.utf8_str(); + return std::string(buffer_utf8.data()); +} + void set_model_events_from_perl(Model &model, int event_object_selection_changed, int event_object_settings_changed, diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 9539cd7cc..9b2fce5b4 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -217,6 +217,8 @@ int combochecklist_get_flags(wxComboCtrl* comboCtrl); wxString L_str(const std::string &str); // Return wxString from std::string in UTF8 wxString from_u8(const std::string &str); +// Return std::string in UTF8 from wxString +std::string into_u8(const wxString &str); void set_model_events_from_perl(Model &model, int event_object_selection_changed, diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 68fbcd612..09a2998b2 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -63,6 +63,7 @@ REGISTER_CLASS(Preset, "GUI::Preset"); REGISTER_CLASS(PresetCollection, "GUI::PresetCollection"); REGISTER_CLASS(PresetBundle, "GUI::PresetBundle"); REGISTER_CLASS(TabIface, "GUI::Tab"); +REGISTER_CLASS(PreviewIface, "GUI::Preview"); REGISTER_CLASS(ProgressStatusBar, "GUI::ProgressStatusBar"); REGISTER_CLASS(PresetUpdater, "PresetUpdater"); REGISTER_CLASS(AppController, "AppController"); diff --git a/xs/src/slic3r/GUI/GUI_Preview.cpp b/xs/src/slic3r/GUI/GUI_Preview.cpp new file mode 100644 index 000000000..bfc8b5623 --- /dev/null +++ b/xs/src/slic3r/GUI/GUI_Preview.cpp @@ -0,0 +1,489 @@ +#include "../../libslic3r/libslic3r.h" +#include "GUI_Preview.hpp" +#include "GUI.hpp" +#include "AppConfig.hpp" +#include "3DScene.hpp" +#include "../../libslic3r/GCode/PreviewData.hpp" +#include "PresetBundle.hpp" + +#include +#include +#include +#include +#include +#include +#include + +// this include must follow the wxWidgets ones or it won't compile on Windows -> see http://trac.wxwidgets.org/ticket/2421 +#include "../../libslic3r/Print.hpp" + +namespace Slic3r { +namespace GUI { + +Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data) + : m_canvas(nullptr) + , m_double_slider_sizer(nullptr) + , m_label_view_type(nullptr) + , m_choice_view_type(nullptr) + , m_label_show_features(nullptr) + , m_combochecklist_features(nullptr) + , m_checkbox_travel(nullptr) + , m_checkbox_retractions(nullptr) + , m_checkbox_unretractions(nullptr) + , m_checkbox_shells(nullptr) + , m_config(config) + , m_print(print) + , m_gcode_preview_data(gcode_preview_data) + , m_number_extruders(1) + , m_preferred_color_mode("feature") + , m_loaded(false) + , m_enabled(false) + , m_force_sliders_full_range(false) +{ + if (init(notebook, config, print, gcode_preview_data)) + { + notebook->AddPage(this, _(L("Preview"))); + show_hide_ui_elements("none"); + load_print(); + } +} + +bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data) +{ + if ((notebook == nullptr) || (config == nullptr) || (print == nullptr) || (gcode_preview_data == nullptr)) + return false; + + // creates this panel add append it to the given notebook as a new page + if (!Create(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize)) + return false; + + int attribList[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24, WX_GL_SAMPLE_BUFFERS, GL_TRUE, WX_GL_SAMPLES, 4, 0 }; + + int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER; + const AppConfig* app_config = GUI::get_app_config(); + bool enable_multisample = (app_config != nullptr) && (app_config->get("use_legacy_opengl") != "1") && (wxVersion >= 30003); + + // if multisample is not enabled or supported by the graphic card, remove it from the attributes list + bool can_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample"); +// bool can_multisample = enable_multisample && wxGLCanvas::IsDisplaySupported(attribList); // <<< Alternative method: but IsDisplaySupported() seems not to work + if (!can_multisample) + attribList[4] = 0; + + m_canvas = new wxGLCanvas(this, wxID_ANY, attribList); + if (m_canvas == nullptr) + return false; + + _3DScene::add_canvas(m_canvas); + _3DScene::allow_multisample(m_canvas, can_multisample); + _3DScene::enable_shader(m_canvas, true); + _3DScene::set_config(m_canvas, m_config); + _3DScene::set_print(m_canvas, m_print); + _3DScene::enable_legend_texture(m_canvas, true); + _3DScene::enable_dynamic_background(m_canvas, true); + + m_double_slider_sizer = new wxBoxSizer(wxHORIZONTAL); + create_double_slider(this, m_double_slider_sizer, m_canvas); + + m_label_view_type = new wxStaticText(this, wxID_ANY, _(L("View"))); + + m_choice_view_type = new wxChoice(this, wxID_ANY); + m_choice_view_type->Append(_(L("Feature type"))); + m_choice_view_type->Append(_(L("Height"))); + m_choice_view_type->Append(_(L("Width"))); + m_choice_view_type->Append(_(L("Speed"))); + m_choice_view_type->Append(_(L("Volumetric flow rate"))); + m_choice_view_type->Append(_(L("Tool"))); + m_choice_view_type->SetSelection(0); + + 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); + std::string feature_text = GUI::into_u8(_(L("Feature types"))); + std::string feature_items = GUI::into_u8( + _(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(m_combochecklist_features, feature_text, feature_items, true); + + m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel"))); + m_checkbox_retractions = new wxCheckBox(this, wxID_ANY, _(L("Retractions"))); + m_checkbox_unretractions = new wxCheckBox(this, wxID_ANY, _(L("Unretractions"))); + m_checkbox_shells = new wxCheckBox(this, wxID_ANY, _(L("Shells"))); + + wxBoxSizer* top_sizer = new wxBoxSizer(wxHORIZONTAL); + top_sizer->Add(m_canvas, 1, wxALL | wxEXPAND, 0); + top_sizer->Add(m_double_slider_sizer, 0, wxEXPAND, 0); + + wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL); + bottom_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->Add(m_choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->AddSpacer(10); + bottom_sizer->Add(m_label_show_features, 0, wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->Add(m_combochecklist_features, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->AddSpacer(20); + bottom_sizer->Add(m_checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->AddSpacer(10); + bottom_sizer->Add(m_checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->AddSpacer(10); + bottom_sizer->Add(m_checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + bottom_sizer->AddSpacer(10); + bottom_sizer->Add(m_checkbox_shells, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + + wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(top_sizer, 1, wxALL | wxEXPAND, 0); + main_sizer->Add(bottom_sizer, 0, wxALL | wxEXPAND, 0); + + SetSizer(main_sizer); + SetMinSize(GetSize()); + GetSizer()->SetSizeHints(this); + + bind_event_handlers(); + + // sets colors for gcode preview extrusion roles + std::vector extrusion_roles_colors = { + "FFFF66", // Perimeter + "FFA500", // External perimeter + "0000FF", // Overhang perimeter + "B1302A", // Internal infill + "D732D7", // Solid infill + "FF1A1A", // Top solid infill + "9999FF", // Bridge infill + "FFFFFF", // Gap fill + "845321", // Skirt + "00FF00", // Support material + "008000", // Support material interface + "B3E3AB", // Wipe tower + "28CC94" // Custom + }; + m_gcode_preview_data->set_extrusion_paths_colors(extrusion_roles_colors); + + return true; +} + +Preview::~Preview() +{ + unbind_event_handlers(); + + if (m_canvas != nullptr) + { + _3DScene::remove_canvas(m_canvas); + delete m_canvas; + } +} + +void Preview::register_on_viewport_changed_callback(void* callback) +{ + if ((m_canvas != nullptr) && (callback != nullptr)) + _3DScene::register_on_viewport_changed_callback(m_canvas, callback); +} + +void Preview::set_number_extruders(unsigned int number_extruders) +{ + if (m_number_extruders != number_extruders) + { + m_number_extruders = number_extruders; + int type = 0; // color by a feature type + if (number_extruders > 1) + { + int tool_idx = m_choice_view_type->FindString(_(L("Tool"))); + int type = (number_extruders > 1) ? tool_idx /* color by a tool number */ : 0; // color by a feature type + m_choice_view_type->SetSelection(type); + if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) + m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type; + + m_preferred_color_mode = (type == tool_idx) ? "tool_or_feature" : "feature"; + } + } +} + +void Preview::reset_gcode_preview_data() +{ + m_gcode_preview_data->reset(); + _3DScene::reset_legend_texture(); +} + +void Preview::set_canvas_as_dirty() +{ + if (m_canvas != nullptr) + _3DScene::set_as_dirty(m_canvas); +} + +void Preview::set_enabled(bool enabled) +{ + m_enabled = enabled; +} + +void Preview::set_bed_shape(const Pointfs& shape) +{ + if (m_canvas != nullptr) + _3DScene::set_bed_shape(m_canvas, shape); +} + +void Preview::select_view(const std::string& direction) +{ + if (m_canvas != nullptr) + _3DScene::select_view(m_canvas, direction); +} + +void Preview::set_viewport_from_scene(wxGLCanvas* canvas) +{ + if ((m_canvas != nullptr) && (canvas != nullptr)) + _3DScene::set_viewport_from_scene(m_canvas, canvas); +} + +void Preview::set_viewport_into_scene(wxGLCanvas* canvas) +{ + if ((m_canvas != nullptr) && (canvas != nullptr)) + _3DScene::set_viewport_from_scene(canvas, m_canvas); +} + +void Preview::set_drop_target(wxDropTarget* target) +{ + if (target != nullptr) + SetDropTarget(target); +} + +void Preview::load_print() +{ + if (m_loaded) + return; + + // 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) + unsigned int n_layers = 0; + if (m_print->is_step_done(posSlice)) + { + std::set zs; + for (const PrintObject* print_object : m_print->objects()) + { + const LayerPtrs& layers = print_object->layers(); + const SupportLayerPtrs& support_layers = print_object->support_layers(); + for (const Layer* layer : layers) + { + zs.insert(layer->print_z); + } + for (const SupportLayer* layer : support_layers) + { + zs.insert(layer->print_z); + } + } + + n_layers = (unsigned int)zs.size(); + } + + if (n_layers == 0) + { + reset_sliders(); + _3DScene::reset_legend_texture(); + if (m_canvas) + m_canvas->Refresh(); + + return; + } + + if (m_preferred_color_mode == "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. + unsigned int number_extruders = (unsigned int)m_print->extruders().size(); + int tool_idx = m_choice_view_type->FindString(_(L("Tool"))); + int type = (number_extruders > 1) ? tool_idx /* color by a tool number */ : 0; // color by a feature type + m_choice_view_type->SetSelection(type); + if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) + m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type; + // If the->SetSelection changed the following line, revert it to "decide yourself". + m_preferred_color_mode = "tool_or_feature"; + } + + // Collect colors per extruder. + std::vector colors; + if (!m_gcode_preview_data->empty() || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool)) + { + const ConfigOptionStrings* extruders_opt = dynamic_cast(m_config->option("extruder_colour")); + const ConfigOptionStrings* filamemts_opt = dynamic_cast(m_config->option("filament_colour")); + unsigned int colors_count = std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size()); + + unsigned char rgb[3]; + for (unsigned int i = 0; i < colors_count; ++i) + { + std::string color = m_config->opt_string("extruder_colour", i); + if (!PresetBundle::parse_color(color, rgb)) + { + color = m_config->opt_string("filament_colour", i); + if (!PresetBundle::parse_color(color, rgb)) + color = "#FFFFFF"; + } + + colors.push_back(color); + } + } + + if (IsShown() && (m_canvas != nullptr)) + { + // used to set the sliders to the extremes of the current zs range + m_force_sliders_full_range = false; + + if (m_gcode_preview_data->empty()) + { + // load skirt and brim + _3DScene::load_preview(m_canvas, colors); + show_hide_ui_elements("simple"); + } + else + { + m_force_sliders_full_range = (_3DScene::get_volumes_count(m_canvas) == 0); + _3DScene::load_gcode_preview(m_canvas, m_gcode_preview_data, colors); + show_hide_ui_elements("full"); + + // recalculates zs and update sliders accordingly + n_layers = (unsigned int)_3DScene::get_current_print_zs(m_canvas, true).size(); + if (n_layers == 0) + { + // all layers filtered out + reset_sliders(); + m_canvas->Refresh(); + } + } + + if (n_layers > 0) + update_sliders(); + + m_loaded = true; + } +} + +void Preview::reload_print(bool force) +{ + _3DScene::reset_volumes(m_canvas); + m_loaded = false; + + if (!IsShown() && !force) + return; + + load_print(); +} + +void Preview::refresh_print() +{ + m_loaded = false; + + if (!IsShown()) + return; + + load_print(); +} + +void Preview::bind_event_handlers() +{ + this->Bind(wxEVT_SIZE, &Preview::on_size, this); + m_choice_view_type->Bind(wxEVT_CHOICE, &Preview::on_choice_view_type, this); + m_combochecklist_features->Bind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_features, this); + m_checkbox_travel->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_travel, this); + m_checkbox_retractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this); + m_checkbox_unretractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_unretractions, this); + m_checkbox_shells->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_shells, this); +} + +void Preview::unbind_event_handlers() +{ + this->Unbind(wxEVT_SIZE, &Preview::on_size, this); + m_choice_view_type->Unbind(wxEVT_CHOICE, &Preview::on_choice_view_type, this); + m_combochecklist_features->Unbind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_features, this); + m_checkbox_travel->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_travel, this); + m_checkbox_retractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this); + m_checkbox_unretractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_unretractions, this); + m_checkbox_shells->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_shells, this); +} + +void Preview::show_hide_ui_elements(const std::string& what) +{ + bool enable = (what == "full"); + m_label_show_features->Enable(enable); + m_combochecklist_features->Enable(enable); + m_checkbox_travel->Enable(enable); + m_checkbox_retractions->Enable(enable); + m_checkbox_unretractions->Enable(enable); + m_checkbox_shells->Enable(enable); + + enable = (what != "none"); + m_label_view_type->Enable(enable); + m_choice_view_type->Enable(enable); +} + +void Preview::reset_sliders() +{ + m_enabled = false; + reset_double_slider(); + m_double_slider_sizer->Hide((size_t)0); +} + +void Preview::update_sliders() +{ + m_enabled = true; + update_double_slider(m_force_sliders_full_range); + m_double_slider_sizer->Show((size_t)0); + Layout(); +} + +void Preview::on_size(wxSizeEvent& evt) +{ + evt.Skip(); + Refresh(); +} + +void Preview::on_choice_view_type(wxCommandEvent& evt) +{ + m_preferred_color_mode = (m_choice_view_type->GetStringSelection() == L("Tool")) ? "tool" : "feature"; + int selection = m_choice_view_type->GetCurrentSelection(); + if ((0 <= selection) && (selection < (int)GCodePreviewData::Extrusion::Num_View_Types)) + m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)selection; + + reload_print(); +} + +void Preview::on_combochecklist_features(wxCommandEvent& evt) +{ + int flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_features); + m_gcode_preview_data->extrusion.role_flags = (unsigned int)flags; + refresh_print(); +} + +void Preview::on_checkbox_travel(wxCommandEvent& evt) +{ + m_gcode_preview_data->travel.is_visible = m_checkbox_travel->IsChecked(); + refresh_print(); +} + +void Preview::on_checkbox_retractions(wxCommandEvent& evt) +{ + m_gcode_preview_data->retraction.is_visible = m_checkbox_retractions->IsChecked(); + refresh_print(); +} + +void Preview::on_checkbox_unretractions(wxCommandEvent& evt) +{ + m_gcode_preview_data->unretraction.is_visible = m_checkbox_unretractions->IsChecked(); + refresh_print(); +} + +void Preview::on_checkbox_shells(wxCommandEvent& evt) +{ + m_gcode_preview_data->shell.is_visible = m_checkbox_shells->IsChecked(); + refresh_print(); +} + +} // namespace GUI +} // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GUI_Preview.hpp b/xs/src/slic3r/GUI/GUI_Preview.hpp new file mode 100644 index 000000000..bdd69a075 --- /dev/null +++ b/xs/src/slic3r/GUI/GUI_Preview.hpp @@ -0,0 +1,91 @@ +#ifndef slic3r_GUI_Preview_hpp_ +#define slic3r_GUI_Preview_hpp_ + +#include +#include "../../libslic3r/Point.hpp" + +#include + +class wxNotebook; +class wxGLCanvas; +class wxBoxSizer; +class wxStaticText; +class wxChoice; +class wxComboCtrl; +class wxCheckBox; + +namespace Slic3r { + +class DynamicPrintConfig; +class Print; +class GCodePreviewData; + +namespace GUI { + +class Preview : public wxPanel +{ + wxGLCanvas* m_canvas; + wxBoxSizer* m_double_slider_sizer; + wxStaticText* m_label_view_type; + wxChoice* m_choice_view_type; + wxStaticText* m_label_show_features; + wxComboCtrl* m_combochecklist_features; + wxCheckBox* m_checkbox_travel; + wxCheckBox* m_checkbox_retractions; + wxCheckBox* m_checkbox_unretractions; + wxCheckBox* m_checkbox_shells; + + DynamicPrintConfig* m_config; + Print* m_print; + GCodePreviewData* m_gcode_preview_data; + + unsigned int m_number_extruders; + std::string m_preferred_color_mode; + + bool m_loaded; + bool m_enabled; + bool m_force_sliders_full_range; + +public: + Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data); + virtual ~Preview(); + + void register_on_viewport_changed_callback(void* callback); + void set_number_extruders(unsigned int number_extruders); + void reset_gcode_preview_data(); + void set_canvas_as_dirty(); + void set_enabled(bool enabled); + void set_bed_shape(const Pointfs& shape); + void select_view(const std::string& direction); + void set_viewport_from_scene(wxGLCanvas* canvas); + void set_viewport_into_scene(wxGLCanvas* canvas); + void set_drop_target(wxDropTarget* target); + + void load_print(); + void reload_print(bool force = false); + void refresh_print(); + +private: + bool init(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data); + + void bind_event_handlers(); + void unbind_event_handlers(); + + void show_hide_ui_elements(const std::string& what); + + void reset_sliders(); + void update_sliders(); + + void on_size(wxSizeEvent& evt); + void on_choice_view_type(wxCommandEvent& evt); + void on_combochecklist_features(wxCommandEvent& evt); + void on_checkbox_travel(wxCommandEvent& evt); + void on_checkbox_retractions(wxCommandEvent& evt); + void on_checkbox_unretractions(wxCommandEvent& evt); + void on_checkbox_shells(wxCommandEvent& evt); +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GUI_Preview_hpp_ diff --git a/xs/src/slic3r/GUI/GUI_PreviewIface.cpp b/xs/src/slic3r/GUI/GUI_PreviewIface.cpp new file mode 100644 index 000000000..9048beb33 --- /dev/null +++ b/xs/src/slic3r/GUI/GUI_PreviewIface.cpp @@ -0,0 +1,62 @@ +#include "../../libslic3r/libslic3r.h" +#include "GUI_PreviewIface.hpp" +#include "GUI_Preview.hpp" + +namespace Slic3r { + +void PreviewIface::register_on_viewport_changed_callback(void* callback) +{ + m_preview->register_on_viewport_changed_callback(callback); +} + +void PreviewIface::set_number_extruders(unsigned int number_extruders) +{ + m_preview->set_number_extruders(number_extruders); +} + +void PreviewIface::reset_gcode_preview_data() +{ + m_preview->reset_gcode_preview_data(); +} + +void PreviewIface::reload_print(bool force) +{ + m_preview->reload_print(force); +} + +void PreviewIface::set_canvas_as_dirty() +{ + m_preview->set_canvas_as_dirty(); +} + +void PreviewIface::set_enabled(bool enabled) +{ + m_preview->set_enabled(enabled); +} + +void PreviewIface::set_bed_shape(const Pointfs& shape) +{ + m_preview->set_bed_shape(shape); +} + +void PreviewIface::select_view(const std::string& direction) +{ + m_preview->select_view(direction); +} + +void PreviewIface::set_viewport_from_scene(wxGLCanvas* canvas) +{ + m_preview->set_viewport_from_scene(canvas); +} + +void PreviewIface::set_viewport_into_scene(wxGLCanvas* canvas) +{ + m_preview->set_viewport_into_scene(canvas); +} + +void PreviewIface::set_drop_target(wxDropTarget* target) +{ + m_preview->set_drop_target(target); +} + +} // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GUI_PreviewIface.hpp b/xs/src/slic3r/GUI/GUI_PreviewIface.hpp new file mode 100644 index 000000000..86f155bd5 --- /dev/null +++ b/xs/src/slic3r/GUI/GUI_PreviewIface.hpp @@ -0,0 +1,37 @@ +#ifndef slic3r_GUI_PreviewIface_hpp_ +#define slic3r_GUI_PreviewIface_hpp_ + +#include "../../libslic3r/Point.hpp" + +class wxGLCanvas; +class wxDropTarget; + +namespace Slic3r { + +namespace GUI { +class Preview; +} // namespace GUI + +class PreviewIface +{ + GUI::Preview* m_preview; + +public: + explicit PreviewIface(GUI::Preview* preview) : m_preview(preview) {} + + void register_on_viewport_changed_callback(void* callback); + void set_number_extruders(unsigned int number_extruders); + void reset_gcode_preview_data(); + void reload_print(bool force = false); + void set_canvas_as_dirty(); + void set_enabled(bool enabled); + void set_bed_shape(const Pointfs& shape); + void select_view(const std::string& direction); + void set_viewport_from_scene(wxGLCanvas* canvas); + void set_viewport_into_scene(wxGLCanvas* canvas); + void set_drop_target(wxDropTarget* target); +}; + +} // namespace Slic3r + +#endif // slic3r_GUI_PreviewIface_hpp_ diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index a4d656616..22e2ff1d7 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -59,6 +59,9 @@ void show_error_id(int id, std::string msg) TabIface* get_preset_tab(char *name) %code%{ RETVAL=Slic3r::GUI::get_preset_tab_iface(name); %}; +PreviewIface* create_preview_iface(SV *ui, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data) + %code%{ RETVAL=Slic3r::GUI::create_preview_iface((wxNotebook*)wxPli_sv_2_object(aTHX_ ui, "Wx::Notebook"), config, print, gcode_preview_data); %}; + bool load_language() %code%{ RETVAL=Slic3r::GUI::load_language(); %}; diff --git a/xs/xsp/GUI_Preview.xsp b/xs/xsp/GUI_Preview.xsp new file mode 100644 index 000000000..da50c0d21 --- /dev/null +++ b/xs/xsp/GUI_Preview.xsp @@ -0,0 +1,28 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "slic3r/GUI/GUI_PreviewIface.hpp" +%} + +%name{Slic3r::GUI::Preview} class PreviewIface { + + void register_on_viewport_changed_callback(SV* callback) + %code%{ THIS->register_on_viewport_changed_callback((void*)callback); %}; + + void set_number_extruders(unsigned int number_extruders); + void reset_gcode_preview_data(); + void reload_print(bool force = false); + void set_canvas_as_dirty(); + void set_enabled(bool enabled); + void set_bed_shape(Pointfs shape); + void select_view(std::string direction); + void set_viewport_from_scene(SV *ui) + %code%{ THIS->set_viewport_from_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ ui, "Wx::GLCanvas")); %}; + + void set_viewport_into_scene(SV *ui) + %code%{ THIS->set_viewport_into_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ ui, "Wx::GLCanvas")); %}; + + void SetDropTarget(SV *ui) + %code%{ THIS->set_drop_target((wxDropTarget*)wxPli_sv_2_object(aTHX_ ui, "Wx::DropTarget")); %}; +}; \ No newline at end of file diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 408966607..a91c40726 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -235,10 +235,12 @@ PresetCollection* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T PresetBundle* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T -TabIface* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -ProgressStatusBar* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T +TabIface* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +PreviewIface* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +ProgressStatusBar* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T PresetUpdater* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 9dd3722b2..0209ce92d 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -215,6 +215,7 @@ %typemap{PresetHints*}; %typemap{Ref}{simple}; %typemap{TabIface*}; +%typemap{PreviewIface*}; %typemap{ProgressStatusBar*}; %typemap{PrintRegionPtrs*};