diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 56038ca9ec..c0718c77be 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -127,6 +127,8 @@ sub new { $range->[1] *= $variation; } $_->set_scaling_factor($scale) for @{ $model_object->instances }; + + $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%"); $object->transform_thumbnail($self->{model}, $obj_idx); #update print and start background processing @@ -2100,7 +2102,8 @@ sub object_list_changed { 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; - my $method = ($have_objects && ! $export_in_progress && $model_fits) ? 'Enable' : 'Disable'; + # $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); } diff --git a/resources/icons/bed/mk2_top.png b/resources/icons/bed/mk2_top.png index 142050c3a2..cab4b966f8 100644 Binary files a/resources/icons/bed/mk2_top.png and b/resources/icons/bed/mk2_top.png differ diff --git a/resources/icons/bed/mk3_top.png b/resources/icons/bed/mk3_top.png index 0403c2f05c..846ca53a5d 100644 Binary files a/resources/icons/bed/mk3_top.png and b/resources/icons/bed/mk3_top.png differ diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp index 2c32db1a67..dd3500eba0 100644 --- a/xs/src/libslic3r/Format/3mf.cpp +++ b/xs/src/libslic3r/Format/3mf.cpp @@ -1989,7 +1989,7 @@ namespace Slic3r { // stores object's name if (!obj->name.empty()) - stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << obj->name << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n"; // stores object's config data for (const std::string& key : obj->config.keys()) @@ -2012,7 +2012,7 @@ namespace Slic3r { // stores volume's name if (!volume->name.empty()) - stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << volume->name << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n"; // stores volume's modifier field if (volume->modifier) diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp index 21d4b4d3b7..600aa6cd97 100644 --- a/xs/src/libslic3r/Format/AMF.cpp +++ b/xs/src/libslic3r/Format/AMF.cpp @@ -8,6 +8,7 @@ #include "../libslic3r.h" #include "../Model.hpp" #include "../GCode.hpp" +#include "../Utils.hpp" #include "../slic3r/GUI/PresetBundle.hpp" #include "AMF.hpp" @@ -686,33 +687,6 @@ bool load_amf(const char *path, PresetBundle* bundle, Model *model) return false; } -std::string xml_escape(std::string text) -{ - std::string::size_type pos = 0; - for (;;) - { - pos = text.find_first_of("\"\'&<>", pos); - if (pos == std::string::npos) - break; - - std::string replacement; - switch (text[pos]) - { - case '\"': replacement = """; break; - case '\'': replacement = "'"; break; - case '&': replacement = "&"; break; - case '<': replacement = "<"; break; - case '>': replacement = ">"; break; - default: break; - } - - text.replace(pos, 1, replacement); - pos += replacement.size(); - } - - return text; -} - bool store_amf(const char *path, Model *model, Print* print, bool export_print_config) { if ((path == nullptr) || (model == nullptr) || (print == nullptr)) @@ -761,7 +735,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c for (const std::string &key : object->config.keys()) stream << " " << object->config.serialize(key) << "\n"; if (!object->name.empty()) - stream << " " << object->name << "\n"; + stream << " " << xml_escape(object->name) << "\n"; std::vector layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector(); if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) { // Store the layer height profile as a single semicolon separated list. @@ -805,7 +779,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c for (const std::string &key : volume->config.keys()) stream << " " << volume->config.serialize(key) << "\n"; if (!volume->name.empty()) - stream << " " << volume->name << "\n"; + stream << " " << xml_escape(volume->name) << "\n"; if (volume->modifier) stream << " 1\n"; for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++i) { diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index f0b37ade32..89a72a7251 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -309,10 +309,12 @@ std::vector>> GCode::collec size_t object_idx; size_t layer_idx; }; - std::vector> per_object(print.objects.size(), std::vector()); + + PrintObjectPtrs printable_objects = print.get_printable_objects(); + std::vector> per_object(printable_objects.size(), std::vector()); std::vector ordering; - for (size_t i = 0; i < print.objects.size(); ++ i) { - per_object[i] = collect_layers_to_print(*print.objects[i]); + for (size_t i = 0; i < printable_objects.size(); ++i) { + per_object[i] = collect_layers_to_print(*printable_objects[i]); OrderingItem ordering_item; ordering_item.object_idx = i; ordering.reserve(ordering.size() + per_object[i].size()); @@ -337,8 +339,8 @@ std::vector>> GCode::collec std::pair> merged; // Assign an average print_z to the set of layers with nearly equal print_z. merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z); - merged.second.assign(print.objects.size(), LayerToPrint()); - for (; i < j; ++ i) { + merged.second.assign(printable_objects.size(), LayerToPrint()); + for (; i < j; ++i) { const OrderingItem &oi = ordering[i]; assert(merged.second[oi.object_idx].layer() == nullptr); merged.second[oi.object_idx] = std::move(per_object[oi.object_idx][oi.layer_idx]); @@ -472,9 +474,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. m_layer_count = 0; + PrintObjectPtrs printable_objects = print.get_printable_objects(); if (print.config.complete_objects.value) { // Add each of the object's layers separately. - for (auto object : print.objects) { + for (auto object : printable_objects) { std::vector zs; zs.reserve(object->layers.size() + object->support_layers.size()); for (auto layer : object->layers) @@ -487,7 +490,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } else { // Print all objects with the same print_z together. std::vector zs; - for (auto object : print.objects) { + for (auto object : printable_objects) { zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); for (auto layer : object->layers) zs.push_back(layer->print_z); @@ -506,8 +509,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) { // get the minimum cross-section used in the print std::vector mm3_per_mm; - for (auto object : print.objects) { - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { + for (auto object : printable_objects) { + for (size_t region_id = 0; region_id < print.regions.size(); ++region_id) { auto region = print.regions[region_id]; for (auto layer : object->layers) { auto layerm = layer->regions[region_id]; @@ -567,7 +570,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) _write(file, "\n"); } // Write some terse information on the slicing parameters. - const PrintObject *first_object = print.objects.front(); + const PrintObject *first_object = printable_objects.front(); const double layer_height = first_object->config.layer_height.value; const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height); for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { @@ -596,13 +599,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) size_t initial_print_object_id = 0; bool has_wipe_tower = false; if (print.config.complete_objects.value) { - // Find the 1st printing object, find its tool ordering and the initial extruder ID. - for (; initial_print_object_id < print.objects.size(); ++initial_print_object_id) { - tool_ordering = ToolOrdering(*print.objects[initial_print_object_id], initial_extruder_id); - if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) - break; - } - } else { + // Find the 1st printing object, find its tool ordering and the initial extruder ID. + for (; initial_print_object_id < printable_objects.size(); ++initial_print_object_id) { + tool_ordering = ToolOrdering(*printable_objects[initial_print_object_id], initial_extruder_id); + if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) + break; + } + } + else { // Find tool ordering for all the objects at once, and the initial extruder ID. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it. tool_ordering = print.m_tool_ordering.empty() ? @@ -676,7 +680,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Collect outer contours of all objects over all layers. // Discard objects only containing thin walls (offset would fail on an empty polygon). Polygons islands; - for (const PrintObject *object : print.objects) + for (const PrintObject *object : printable_objects) for (const Layer *layer : object->layers) for (const ExPolygon &expoly : layer->slices.expolygons) for (const Point © : object->_shifted_copies) { @@ -724,7 +728,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) if (print.config.complete_objects.value) { // Print objects from the smallest to the tallest to avoid collisions // when moving onto next object starting point. - std::vector objects(print.objects); + std::vector objects(printable_objects); std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; }); size_t finished_objects = 0; for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { @@ -788,7 +792,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) PrintObjectPtrs printable_objects = print.get_printable_objects(); for (PrintObject *object : printable_objects) object_reference_points.push_back(object->_shifted_copies.front()); - Slic3r::Geometry::chained_path(object_reference_points, object_indices); + Slic3r::Geometry::chained_path(object_reference_points, object_indices); // Sort layers by Z. // All extrusion moves with the same top layer height are extruded uninterrupted. std::vector>> layers_to_print = collect_layers_to_print(print); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 9b3f2694fb..189a94d496 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -451,10 +451,9 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it // we will sort objects so that dedicated for wiping are at the beginning: - PrintObjectPtrs object_list = print.objects; + PrintObjectPtrs object_list = print.get_printable_objects(); std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; }); - // We will now iterate through // - first the dedicated objects to mark perimeters or infills (depending on infill_first) // - second through the dedicated ones again to mark infills or perimeters (depending on infill_first) @@ -548,7 +547,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config); unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config); - for (const PrintObject* object : print.objects) { + PrintObjectPtrs printable_objects = print.get_printable_objects(); + for (const PrintObject* object : printable_objects) { // Finds this layer: auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers.end()) diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp index a501fa4d3a..3492228543 100644 --- a/xs/src/libslic3r/Utils.hpp +++ b/xs/src/libslic3r/Utils.hpp @@ -84,6 +84,8 @@ inline T next_highest_power_of_2(T v) return ++ v; } +extern std::string xml_escape(std::string text); + class PerlCallback { public: PerlCallback(void *sv) : m_callback(nullptr) { this->register_callback(sv); } diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 13ec1d0661..55164bbdd6 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -387,4 +387,31 @@ unsigned get_current_pid() #endif } +std::string xml_escape(std::string text) +{ + std::string::size_type pos = 0; + for (;;) + { + pos = text.find_first_of("\"\'&<>", pos); + if (pos == std::string::npos) + break; + + std::string replacement; + switch (text[pos]) + { + case '\"': replacement = """; break; + case '\'': replacement = "'"; break; + case '&': replacement = "&"; break; + case '<': replacement = "<"; break; + case '>': replacement = ">"; break; + default: break; + } + + text.replace(pos, 1, replacement); + pos += replacement.size(); + } + + return text; +} + }; // namespace Slic3r diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 2ffd788eb2..62659033ad 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1651,7 +1651,7 @@ void _3DScene::update_volumes_selection(wxGLCanvas* canvas, const std::vector& selections); - static bool check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config); + static int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config); static bool move_volume_up(wxGLCanvas* canvas, unsigned int id); static bool move_volume_down(wxGLCanvas* canvas, unsigned int id); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 064a9adce9..722f1c1124 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1878,9 +1878,11 @@ void GLCanvas3D::update_volumes_selection(const std::vector& selections) } } -bool GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const +int GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const { - return m_volumes.check_outside_state(config, nullptr); + ModelInstance::EPrintVolumeState state; + m_volumes.check_outside_state(config, &state); + return (int)state; } bool GLCanvas3D::move_volume_up(unsigned int id) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index d18ca0cabe..a9a6117ecc 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -495,7 +495,7 @@ public: void deselect_volumes(); void select_volume(unsigned int id); void update_volumes_selection(const std::vector& selections); - bool check_volumes_outside_state(const DynamicPrintConfig* config) const; + int check_volumes_outside_state(const DynamicPrintConfig* config) const; bool move_volume_up(unsigned int id); bool move_volume_down(unsigned int id); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 23a8f4c15c..5e9048d541 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -237,7 +237,7 @@ void GLCanvas3DManager::update_volumes_selection(wxGLCanvas* canvas, const std:: it->second->update_volumes_selection(selections); } -bool GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const +int GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const { CanvasesMap::const_iterator it = _get_canvas(canvas); return (it != m_canvases.end()) ? it->second->check_volumes_outside_state(config) : false; diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 98205982fb..32aa712d35 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -75,7 +75,7 @@ public: void deselect_volumes(wxGLCanvas* canvas); void select_volume(wxGLCanvas* canvas, unsigned int id); void update_volumes_selection(wxGLCanvas* canvas, const std::vector& selections); - bool check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const; + int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const; bool move_volume_up(wxGLCanvas* canvas, unsigned int id); bool move_volume_down(wxGLCanvas* canvas, unsigned int id); diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 2af555707f..18c9f5dea0 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -79,7 +79,8 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap if (generate_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards - _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); } else @@ -149,14 +150,14 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glDisable(GL_BLEND); } -void GLTexture::_generate_mipmaps(wxImage& image) +unsigned int GLTexture::_generate_mipmaps(wxImage& image) { int w = image.GetWidth(); int h = image.GetHeight(); GLint level = 0; std::vector data(w * h * 4, 0); - while ((w > 1) && (h > 1)) + while ((w > 1) || (h > 1)) { ++level; @@ -183,6 +184,8 @@ void GLTexture::_generate_mipmaps(wxImage& image) ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); } + + return (unsigned int)level; } } // namespace GUI diff --git a/xs/src/slic3r/GUI/GLTexture.hpp b/xs/src/slic3r/GUI/GLTexture.hpp index 2e936161e3..3113fcab20 100644 --- a/xs/src/slic3r/GUI/GLTexture.hpp +++ b/xs/src/slic3r/GUI/GLTexture.hpp @@ -32,7 +32,7 @@ namespace GUI { static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); protected: - void _generate_mipmaps(wxImage& image); + unsigned int _generate_mipmaps(wxImage& image); }; } // namespace GUI diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 38c85c3283..5c2f7df854 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -230,7 +230,7 @@ update_volumes_selection(canvas, selections) CODE: _3DScene::update_volumes_selection((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), selections); -bool +int check_volumes_outside_state(canvas, config) SV *canvas; DynamicPrintConfig *config;