diff --git a/resources/shaders/printbed.fs b/resources/shaders/printbed.fs index d1316ca2fe..bef0751580 100644 --- a/resources/shaders/printbed.fs +++ b/resources/shaders/printbed.fs @@ -1,6 +1,6 @@ #version 110 -const vec3 back_color_dark = vec3(0.235, 0.235, 0.235); +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; diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index 7633017f12..3b3f8875d2 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,14 +1,9 @@ #version 110 -attribute vec3 v_position; -attribute vec2 v_tex_coords; - varying vec2 tex_coords; void main() { - gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position.x, v_position.y, v_position.z, 1.0); - // the following line leads to crash on some Intel graphics card - //gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0); - tex_coords = v_tex_coords; + gl_Position = ftransform(); + tex_coords = gl_MultiTexCoord0.xy; } diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 5bde6c1288..4483d60102 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -836,6 +836,7 @@ extern "C" { "leak:libnvidia-glcore.so\n" // For NVidia driver. "leak:libnvidia-tls.so\n" // For NVidia driver. "leak:terminator_CreateDevice\n" // For Intel Vulkan drivers. + "leak:swrast_dri.so\n" // For Mesa 3D software driver. ; } } diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp index f7a5c50071..d2ff650974 100644 --- a/src/libslic3r/Extruder.cpp +++ b/src/libslic3r/Extruder.cpp @@ -1,4 +1,5 @@ #include "Extruder.hpp" +#include "GCodeWriter.hpp" #include "PrintConfig.hpp" namespace Slic3r { @@ -7,24 +8,24 @@ Extruder::Extruder(unsigned int id, GCodeConfig *config) : m_id(id), m_config(config) { - reset(); - // cache values that are going to be called often m_e_per_mm3 = this->extrusion_multiplier(); if (! m_config->use_volumetric_e) m_e_per_mm3 /= this->filament_crossection(); } -double Extruder::extrude(double dE) +std::pair Extruder::extrude(double dE) { // in case of relative E distances we always reset to 0 before any output if (m_config->use_relative_e_distances) m_E = 0.; + // Quantize extruder delta to G-code resolution. + dE = GCodeFormatter::quantize_e(dE); m_E += dE; m_absolute_E += dE; if (dE < 0.) m_retracted -= dE; - return dE; + return std::make_pair(dE, m_E); } /* This method makes sure the extruder is retracted by the specified amount @@ -34,28 +35,33 @@ double Extruder::extrude(double dE) The restart_extra argument sets the extra length to be used for unretraction. If we're actually performing a retraction, any restart_extra value supplied will overwrite the previous one if any. */ -double Extruder::retract(double length, double restart_extra) +std::pair Extruder::retract(double retract_length, double restart_extra) { // in case of relative E distances we always reset to 0 before any output if (m_config->use_relative_e_distances) m_E = 0.; - double to_retract = std::max(0., length - m_retracted); + // Quantize extruder delta to G-code resolution. + double to_retract = this->retract_to_go(retract_length); if (to_retract > 0.) { m_E -= to_retract; m_absolute_E -= to_retract; m_retracted += to_retract; - m_restart_extra = restart_extra; + m_restart_extra = restart_extra; } - return to_retract; + return std::make_pair(to_retract, m_E); } -double Extruder::unretract() +double Extruder::retract_to_go(double retract_length) const { - double dE = m_retracted + m_restart_extra; - this->extrude(dE); + return std::max(0., GCodeFormatter::quantize_e(retract_length - m_retracted)); +} + +std::pair Extruder::unretract() +{ + auto [dE, emitE] = this->extrude(m_retracted + m_restart_extra); m_retracted = 0.; m_restart_extra = 0.; - return dE; + return std::make_pair(dE, emitE); } // Used filament volume in mm^3. diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index e9c6927f85..7491b1c8f5 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -12,22 +12,24 @@ class Extruder { public: Extruder(unsigned int id, GCodeConfig *config); - virtual ~Extruder() {} - - void reset() { - m_E = 0; - m_absolute_E = 0; - m_retracted = 0; - m_restart_extra = 0; - } + ~Extruder() = default; unsigned int id() const { return m_id; } - double extrude(double dE); - double retract(double length, double restart_extra); - double unretract(); - double E() const { return m_E; } - void reset_E() { m_E = 0.; } + // Following three methods emit: + // first - extrusion delta + // second - number to emit to G-code: This may be delta for relative mode or a distance from last reset_E() for absolute mode. + // They also quantize the E axis to G-code resolution. + std::pair extrude(double dE); + std::pair retract(double retract_length, double restart_extra); + std::pair unretract(); + // How much to retract yet before retract_length is reached? + // The value is quantized to G-code resolution. + double retract_to_go(double retract_length) const; + + // Reset the current state of the E axis (this is only needed for relative extruder addressing mode anyways). + // Returns true if the extruder was non-zero before reset. + bool reset_E() { bool modified = m_E != 0; m_E = 0.; return modified; } double e_per_mm(double mm3_per_mm) const { return mm3_per_mm * m_e_per_mm3; } double e_per_mm3() const { return m_e_per_mm3; } // Used filament volume in mm^3. @@ -57,14 +59,16 @@ private: GCodeConfig *m_config; // Print-wide global ID of this extruder. unsigned int m_id; - // Current state of the extruder axis, may be resetted if use_relative_e_distances. - double m_E; + // Current state of the extruder axis. + // For absolute extruder addressing, it is the current state since the last reset (G92 E0) issued at the end of the last retraction. + // For relative extruder addressing, it is the E axis difference emitted into the G-code the last time. + double m_E { 0 }; // Current state of the extruder tachometer, used to output the extruded_volume() and used_filament() statistics. - double m_absolute_E; + double m_absolute_E { 0 }; // Current positive amount of retraction. - double m_retracted; + double m_retracted { 0 }; // When retracted, this value stores the extra amount of priming on deretraction. - double m_restart_extra; + double m_restart_extra { 0 }; double m_e_per_mm3; }; @@ -76,4 +80,4 @@ inline bool operator> (const Extruder &e1, const Extruder &e2) { return e1.id() } -#endif +#endif // slic3r_Extruder_hpp_ diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ba51196ddc..6a53917de1 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -155,63 +154,52 @@ namespace Slic3r { std::string Wipe::wipe(GCode& gcodegen, bool toolchange) { - std::string gcode; + std::string gcode; + const Extruder &extruder = *gcodegen.writer().extruder(); - /* Reduce feedrate a bit; travel speed is often too high to move on existing material. - Too fast = ripping of existing material; too slow = short wipe path, thus more blob. */ - double wipe_speed = gcodegen.writer().config.travel_speed.value * 0.8; - - // get the retraction length - double length = toolchange - ? gcodegen.writer().extruder()->retract_length_toolchange() - : gcodegen.writer().extruder()->retract_length(); - // Shorten the retraction length by the amount already retracted before wipe. - length *= (1. - gcodegen.writer().extruder()->retract_before_wipe()); - - if (length > 0) { - /* Calculate how long we need to travel in order to consume the required - amount of retraction. In other words, how far do we move in XY at wipe_speed - for the time needed to consume retract_length at retract_speed? */ - double wipe_dist = scale_(length / gcodegen.writer().extruder()->retract_speed() * wipe_speed); - - /* Take the stored wipe path and replace first point with the current actual position - (they might be different, for example, in case of loop clipping). */ - Polyline wipe_path; - wipe_path.append(gcodegen.last_pos()); - wipe_path.append( - this->path.points.begin() + 1, - this->path.points.end() - ); - - wipe_path.clip_end(wipe_path.length() - wipe_dist); - - // subdivide the retraction in segments - if (!wipe_path.empty()) { - // add tag for processor + // Remaining quantized retraction length. + if (double retract_length = extruder.retract_to_go(toolchange ? extruder.retract_length_toolchange() : extruder.retract_length()); + retract_length > 0 && this->path.size() >= 2) { + // Reduce feedrate a bit; travel speed is often too high to move on existing material. + // Too fast = ripping of existing material; too slow = short wipe path, thus more blob. + const double wipe_speed = gcodegen.writer().config.travel_speed.value * 0.8; + // Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one + // due to rounding (TODO: test and/or better math for this). + const double xy_to_e = 0.95 * extruder.retract_speed() / wipe_speed; + // Start with the current position, which may be different from the wipe path start in case of loop clipping. + Vec2d prev = gcodegen.point_to_gcode_quantized(gcodegen.last_pos()); + auto it = this->path.points.begin(); + Vec2d p = gcodegen.point_to_gcode_quantized(*(++ it)); + if (p != prev) { gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Start) + "\n"; - for (const Line& line : wipe_path.lines()) { - double segment_length = line.length(); - /* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one - due to rounding (TODO: test and/or better math for this) */ - double dE = length * (segment_length / wipe_dist) * 0.95; + auto end = this->path.points.end(); + bool done = false; + for (; it != end; ++ it) { + p = gcodegen.point_to_gcode_quantized(*it); + double segment_length = (p - prev).norm(); + double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length); + if (dE > retract_length - EPSILON) { + if (dE > retract_length + EPSILON) + // Shorten the segment. + p = prev + (p - prev) * (retract_length / dE); + dE = retract_length; + done = true; + } //FIXME one shall not generate the unnecessary G1 Fxxx commands, here wipe_speed is a constant inside this cycle. // Is it here for the cooling markers? Or should it be outside of the cycle? - gcode += gcodegen.writer().set_speed(wipe_speed * 60, "", gcodegen.enable_cooling_markers() ? ";_WIPE" : ""); - gcode += gcodegen.writer().extrude_to_xy( - gcodegen.point_to_gcode(line.b), - -dE, - "wipe and retract" - ); + gcode += gcodegen.writer().set_speed(wipe_speed * 60, {}, gcodegen.enable_cooling_markers() ? ";_WIPE" : ""); + gcode += gcodegen.writer().extrude_to_xy(p, -dE, "wipe and retract"); + prev = p; + retract_length -= dE; } // add tag for processor gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n"; - gcodegen.set_last_pos(wipe_path.points.back()); + gcodegen.set_last_pos(gcodegen.gcode_to_point(prev)); } - - // prevent wiping again on same path - this->reset_path(); } + // Prevent wiping again on the same path. + this->reset_path(); return gcode; } @@ -1119,11 +1107,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Write information on the generator. file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str()); - GCodeThumbnails::export_thumbnails_to_file(thumbnail_cb, - print.full_print_config().option("thumbnails")->values, - print.full_print_config().opt_enum("thumbnails_format"), - [&file](const char* sz) { file.write(sz); }, - [&print]() { print.throw_if_canceled(); }); + // Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format". + // If "thumbnails_format" is not defined, export to PNG. + if (const auto [thumbnails, thumbnails_format] = std::make_pair( + print.full_print_config().option("thumbnails"), + print.full_print_config().option>("thumbnails_format")); + thumbnails) + GCodeThumbnails::export_thumbnails_to_file( + thumbnail_cb, thumbnails->values, thumbnails_format ? thumbnails_format->value : GCodeThumbnailsFormat::PNG, + [&file](const char* sz) { file.write(sz); }, + [&print]() { print.throw_if_canceled(); }); // Write notes (content of the Print Settings tab -> Notes) { @@ -3005,13 +2998,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double path_length = 0.; { std::string comment = m_config.gcode_comments ? description : ""; - for (const Line &line : path.polyline.lines()) { - const double line_length = line.length() * SCALING_FACTOR; + Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front()); + auto it = path.polyline.points.begin(); + auto end = path.polyline.points.end(); + for (++ it; it != end; ++ it) { + Vec2d p = this->point_to_gcode_quantized(*it); + const double line_length = (p - prev).norm(); path_length += line_length; - gcode += m_writer.extrude_to_xy( - this->point_to_gcode(line.b), - e_per_mm * line_length, - comment); + gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); + prev = p; } } if (m_enable_cooling_markers) @@ -3234,7 +3229,13 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) Vec2d GCode::point_to_gcode(const Point &point) const { Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); - return unscale(point) + m_origin - extruder_offset; + return unscaled(point) + m_origin - extruder_offset; +} + +Vec2d GCode::point_to_gcode_quantized(const Point &point) const +{ + Vec2d p = this->point_to_gcode(point); + return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) }; } // convert a model-space scaled point into G-code coordinates diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index f46558c353..c0e636c797 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -55,9 +55,9 @@ public: Polyline path; Wipe() : enable(false) {} - bool has_path() const { return !this->path.points.empty(); } - void reset_path() { this->path = Polyline(); } - std::string wipe(GCode &gcodegen, bool toolchange = false); + bool has_path() const { return ! this->path.empty(); } + void reset_path() { this->path.clear(); } + std::string wipe(GCode &gcodegen, bool toolchange); }; class WipeTowerIntegration { @@ -151,7 +151,10 @@ public: void set_origin(const Vec2d &pointf); void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); } const Point& last_pos() const { return m_last_pos; } + // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset. Vec2d point_to_gcode(const Point &point) const; + // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset and quantized to G-code resolution. + Vec2d point_to_gcode_quantized(const Point &point) const; Point gcode_to_point(const Vec2d &point) const; const FullPrintConfig &config() const { return m_config; } const Layer* layer() const { return m_layer; } diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 995964eb5f..58e8ed787a 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1955,7 +1955,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers if (!m_result.spiral_vase_layers.empty() && m_end_position[Z] == m_result.spiral_vase_layers.back().first) m_result.spiral_vase_layers.back().second.second = move_id; else - m_result.spiral_vase_layers.push_back({ m_end_position[Z], { move_id, move_id } }); + m_result.spiral_vase_layers.push_back({ static_cast(m_end_position[Z]), { move_id, move_id } }); } #endif // ENABLE_SPIRAL_VASE_LAYERS return; @@ -2505,7 +2505,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) AxisCoords delta_pos; for (unsigned char a = X; a <= E; ++a) { delta_pos[a] = m_end_position[a] - m_start_position[a]; - max_abs_delta = std::max(max_abs_delta, std::abs(delta_pos[a])); + max_abs_delta = std::max(max_abs_delta, std::abs(delta_pos[a])); } // no displacement, return @@ -2615,7 +2615,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) if (curr.abs_axis_feedrate[a] != 0.0f) { float axis_max_feedrate = get_axis_max_feedrate(static_cast(i), static_cast(a)); if (axis_max_feedrate != 0.0f) - min_feedrate_factor = std::min(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]); + min_feedrate_factor = std::min(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]); } } @@ -3279,7 +3279,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type) #else Vec3f(m_end_position[X], m_end_position[Y], m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]) + m_extruder_offsets[m_extruder_id], #endif // ENABLE_Z_OFFSET_CORRECTION - m_end_position[E] - m_start_position[E], + static_cast(m_end_position[E] - m_start_position[E]), m_feedrate, m_width, m_height, diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 153f4a9c5c..7e4bb831d8 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -178,7 +178,7 @@ namespace Slic3r { #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING private: - using AxisCoords = std::array; + using AxisCoords = std::array; using ExtruderColors = std::vector; using ExtruderTemps = std::vector; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 9dc9f3f96e..870096bb9b 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -74,7 +74,7 @@ static double calc_max_layer_height(const PrintConfig &config, double max_object { double max_layer_height = std::numeric_limits::max(); for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) { - double mlh = config.max_layer_height.values[i]; + double mlh = config.max_layer_height.get_at(i); if (mlh == 0.) mlh = 0.75 * config.nozzle_diameter.values[i]; max_layer_height = std::min(max_layer_height, mlh); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 233976b195..c5279c0f56 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -79,7 +79,7 @@ std::string GCodeWriter::postamble() const std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, int tool) const { if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish))) - return ""; + return {}; std::string code, comment; if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRapFirmware)) { @@ -192,32 +192,18 @@ std::string GCodeWriter::set_acceleration(unsigned int acceleration) std::string GCodeWriter::reset_e(bool force) { - if (FLAVOR_IS(gcfMach3) - || FLAVOR_IS(gcfMakerWare) - || FLAVOR_IS(gcfSailfish)) - return ""; - - if (m_extruder != nullptr) { - if (m_extruder->E() == 0. && ! force) - return ""; - m_extruder->reset_E(); - } - - if (! m_extrusion_axis.empty() && ! this->config.use_relative_e_distances) { - std::ostringstream gcode; - gcode << "G92 " << m_extrusion_axis << "0"; - if (this->config.gcode_comments) gcode << " ; reset extrusion distance"; - gcode << "\n"; - return gcode.str(); - } else { - return ""; - } + return + FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish) || this->config.use_relative_e_distances || + (m_extruder != nullptr && ! m_extruder->reset_E() && ! force) || + m_extrusion_axis.empty() ? + std::string{} : + std::string("G92 ") + m_extrusion_axis + (this->config.gcode_comments ? "0 ; reset extrusion distance\n" : "0\n"); } std::string GCodeWriter::update_progress(unsigned int num, unsigned int tot, bool allow_100) const { if (FLAVOR_IS_NOT(gcfMakerWare) && FLAVOR_IS_NOT(gcfSailfish)) - return ""; + return {}; unsigned int percent = (unsigned int)floor(100.0 * num / tot + 0.5); if (!allow_100) percent = std::min(percent, (unsigned int)99); @@ -269,8 +255,8 @@ std::string GCodeWriter::set_speed(double F, const std::string &comment, const s std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &comment) { - m_pos(0) = point(0); - m_pos(1) = point(1); + m_pos.x() = point.x(); + m_pos.y() = point.y(); GCodeG1Formatter w; w.emit_xy(point); @@ -290,9 +276,9 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co don't perform the Z move but we only move in the XY plane and adjust the nominal Z by reducing the lift amount that will be used for unlift. */ - if (!this->will_move_z(point(2))) { - double nominal_z = m_pos(2) - m_lifted; - m_lifted -= (point(2) - nominal_z); + if (!this->will_move_z(point.z())) { + double nominal_z = m_pos.z() - m_lifted; + m_lifted -= (point.z() - nominal_z); // In case that retract_lift == layer_height we could end up with almost zero in_m_lifted // and a retract could be skipped (https://github.com/prusa3d/PrusaSlicer/issues/2154 if (std::abs(m_lifted) < EPSILON) @@ -318,11 +304,11 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment) we don't perform the move but we only adjust the nominal Z by reducing the lift amount that will be used for unlift. */ if (!this->will_move_z(z)) { - double nominal_z = m_pos(2) - m_lifted; + double nominal_z = m_pos.z() - m_lifted; m_lifted -= (z - nominal_z); if (std::abs(m_lifted) < EPSILON) m_lifted = 0.; - return ""; + return {}; } /* In all the other cases, we perform an actual Z move and cancel @@ -333,7 +319,7 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment) std::string GCodeWriter::_travel_to_z(double z, const std::string &comment) { - m_pos(2) = z; + m_pos.z() = z; double speed = this->config.travel_speed_z.value; if (speed == 0.) @@ -351,8 +337,8 @@ bool GCodeWriter::will_move_z(double z) const /* If target Z is lower than current Z but higher than nominal Z we don't perform an actual Z move. */ if (m_lifted > 0) { - double nominal_z = m_pos(2) - m_lifted; - if (z >= nominal_z && z <= m_pos(2)) + double nominal_z = m_pos.z() - m_lifted; + if (z >= nominal_z && z <= m_pos.z()) return false; } return true; @@ -360,17 +346,17 @@ bool GCodeWriter::will_move_z(double z) const std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std::string &comment) { - m_pos(0) = point(0); - m_pos(1) = point(1); - m_extruder->extrude(dE); + m_pos.x() = point.x(); + m_pos.y() = point.y(); GCodeG1Formatter w; w.emit_xy(point); - w.emit_e(m_extrusion_axis, m_extruder->E()); + w.emit_e(m_extrusion_axis, m_extruder->extrude(dE).second); w.emit_comment(this->config.gcode_comments, comment); return w.string(); } +#if 0 std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment) { m_pos = point; @@ -383,6 +369,7 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std w.emit_comment(this->config.gcode_comments, comment); return w.string(); } +#endif std::string GCodeWriter::retract(bool before_wipe) { @@ -422,14 +409,13 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std restart_extra = restart_extra * area; } - std::string gcode; - if (double dE = m_extruder->retract(length, restart_extra); dE != 0) { + if (auto [dE, emitE] = m_extruder->retract(length, restart_extra); dE != 0) { if (this->config.use_firmware_retraction) { gcode = FLAVOR_IS(gcfMachinekit) ? "G22 ; retract\n" : "G10 ; retract\n"; } else if (! m_extrusion_axis.empty()) { GCodeG1Formatter w; - w.emit_e(m_extrusion_axis, m_extruder->E()); + w.emit_e(m_extrusion_axis, emitE); w.emit_f(m_extruder->retract_speed() * 60.); w.emit_comment(this->config.gcode_comments, comment); gcode = w.string(); @@ -449,14 +435,14 @@ std::string GCodeWriter::unretract() if (FLAVOR_IS(gcfMakerWare)) gcode = "M101 ; extruder on\n"; - if (double dE = m_extruder->unretract(); dE != 0) { + if (auto [dE, emitE] = m_extruder->unretract(); dE != 0) { if (this->config.use_firmware_retraction) { gcode += FLAVOR_IS(gcfMachinekit) ? "G23 ; unretract\n" : "G11 ; unretract\n"; gcode += this->reset_e(); } else if (! m_extrusion_axis.empty()) { // use G1 instead of G0 because G0 will blend the restart with the previous travel move GCodeG1Formatter w; - w.emit_e(m_extrusion_axis, m_extruder->E()); + w.emit_e(m_extrusion_axis, emitE); w.emit_f(m_extruder->deretract_speed() * 60.); w.emit_comment(this->config.gcode_comments, " ; unretract"); gcode += w.string(); @@ -476,21 +462,21 @@ std::string GCodeWriter::lift() { double above = this->config.retract_lift_above.get_at(m_extruder->id()); double below = this->config.retract_lift_below.get_at(m_extruder->id()); - if (m_pos(2) >= above && (below == 0 || m_pos(2) <= below)) + if (m_pos.z() >= above && (below == 0 || m_pos.z() <= below)) target_lift = this->config.retract_lift.get_at(m_extruder->id()); } if (m_lifted == 0 && target_lift > 0) { m_lifted = target_lift; - return this->_travel_to_z(m_pos(2) + target_lift, "lift Z"); + return this->_travel_to_z(m_pos.z() + target_lift, "lift Z"); } - return ""; + return {}; } std::string GCodeWriter::unlift() { std::string gcode; if (m_lifted > 0) { - gcode += this->_travel_to_z(m_pos(2) - m_lifted, "restore layer Z"); + gcode += this->_travel_to_z(m_pos.z() - m_lifted, "restore layer Z"); m_lifted = 0; } return gcode; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index e8a54737e0..6c36c0d3ac 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -61,7 +61,7 @@ public: std::string travel_to_z(double z, const std::string &comment = std::string()); bool will_move_z(double z) const; std::string extrude_to_xy(const Vec2d &point, double dE, const std::string &comment = std::string()); - std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment = std::string()); +// std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment = std::string()); std::string retract(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false); std::string unretract(); @@ -121,6 +121,14 @@ public: // static constexpr const int E_EXPORT_DIGITS = 9; #endif + static constexpr const std::array pow_10 { 1., 10., 100., 1000., 10000., 100000., 1000000., 10000000., 100000000., 1000000000.}; + static constexpr const std::array pow_10_inv{1./1., 1./10., 1./100., 1./1000., 1./10000., 1./100000., 1./1000000., 1./10000000., 1./100000000., 1./1000000000.}; + + // Quantize doubles to a resolution of the G-code. + static double quantize(double v, size_t ndigits) { return std::round(v * pow_10[ndigits]) * pow_10_inv[ndigits]; } + static double quantize_xyzf(double v) { return quantize(v, XYZF_EXPORT_DIGITS); } + static double quantize_e(double v) { return quantize(v, E_EXPORT_DIGITS); } + void emit_axis(const char axis, const double v, size_t digits); void emit_xy(const Vec2d &point) { diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index b6e4802bbb..c5e312a2bf 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -346,10 +346,11 @@ private: friend class Print; PrintObject(Print* print, ModelObject* model_object, const Transform3d& trafo, PrintInstances&& instances); - ~PrintObject() { + ~PrintObject() override { if (m_shared_regions && --m_shared_regions->m_ref_cnt == 0) delete m_shared_regions; clear_layers(); + clear_support_layers(); } void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { m_config.apply(other, ignore_nonexistent); } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 67bd2639b4..195fc9e172 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -3754,6 +3754,7 @@ void modulate_extrusion_by_overlapping_layers( assert(path != nullptr); polylines.emplace_back(Polyline(std::move(path->polyline))); path_ends.emplace_back(std::pair(polylines.back().points.front(), polylines.back().points.back())); + delete path; } } // Destroy the original extrusion paths, their polylines were moved to path_fragments already. diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c4f1a4407c..c8ca2397bb 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -27,6 +27,7 @@ static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0 namespace Slic3r { namespace GUI { +#if !ENABLE_GLBEGIN_GLEND_REMOVAL bool GeometryBuffer::set_from_triangles(const std::vector &triangles, float z) { if (triangles.empty()) { @@ -95,6 +96,7 @@ const float* GeometryBuffer::get_vertices_data() const { return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr; } +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL const float Bed3D::Axes::DefaultStemRadius = 0.5f; const float Bed3D::Axes::DefaultStemLength = 25.0f; @@ -198,6 +200,13 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c m_model_filename = model_filename; m_extended_bounding_box = this->calc_extended_bounding_box(); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + m_contour = ExPolygon(Polygon::new_scale(bed_shape)); + m_polygon = offset(m_contour.contour, (float)m_contour.contour.bounding_box().radius() * 1.7f, jtRound, scale_(0.5)).front(); + + m_triangles.reset(); + m_gridlines.reset(); +#else ExPolygon poly{ Polygon::new_scale(bed_shape) }; calc_triangles(poly); @@ -205,9 +214,10 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c const BoundingBox& bed_bbox = poly.contour.bounding_box(); calc_gridlines(poly, bed_bbox); - m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0]; + m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5)).front(); this->release_VBOs(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL m_texture.reset(); m_model.reset(); @@ -288,6 +298,104 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const return out; } +#if ENABLE_GLBEGIN_GLEND_REMOVAL +void Bed3D::init_triangles() +{ + if (m_triangles.is_initialized()) + return; + + if (m_contour.empty()) + return; + + const std::vector triangles = triangulate_expolygon_2f(m_contour, NORMALS_UP); + if (triangles.empty() || triangles.size() % 3 != 0) + return; + + const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, index_type }; + + Vec2f min = triangles.front(); + Vec2f max = min; + for (const Vec2f& v : triangles) { + min = min.cwiseMin(v).eval(); + max = max.cwiseMax(v).eval(); + } + + const Vec2f size = max - min; + if (size.x() <= 0.0f || size.y() <= 0.0f) + return; + + Vec2f inv_size = size.cwiseInverse(); + inv_size.y() *= -1.0f; + + unsigned int vertices_counter = 0; + for (const Vec2f& v : triangles) { + const Vec3f p = { v.x(), v.y(), GROUND_Z }; + init_data.add_vertex(p, (Vec2f)v.cwiseProduct(inv_size).eval()); + ++vertices_counter; + if (vertices_counter % 3 == 0) { + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); + else + init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + } + } + + m_triangles.init_from(std::move(init_data)); +} + +void Bed3D::init_gridlines() +{ + if (m_gridlines.is_initialized()) + return; + + if (m_contour.empty()) + return; + + const BoundingBox& bed_bbox = m_contour.contour.bounding_box(); + const coord_t step = scale_(10.0); + + Polylines axes_lines; + for (coord_t x = bed_bbox.min.x(); x <= bed_bbox.max.x(); x += step) { + Polyline line; + line.append(Point(x, bed_bbox.min.y())); + line.append(Point(x, bed_bbox.max.y())); + axes_lines.push_back(line); + } + for (coord_t y = bed_bbox.min.y(); y <= bed_bbox.max.y(); y += step) { + Polyline line; + line.append(Point(bed_bbox.min.x(), y)); + line.append(Point(bed_bbox.max.x(), 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(m_contour, float(SCALED_EPSILON)))); + + // append bed contours + Lines contour_lines = to_lines(m_contour); + std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); + + const GLModel::Geometry::EIndexType index_type = (gridlines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + + for (const Line& l : gridlines) { + init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), GROUND_Z)); + init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), GROUND_Z)); + const unsigned int vertices_counter = (unsigned int)init_data.vertices_count(); + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); + else + init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + } + + m_gridlines.init_from(std::move(init_data)); +} +#else void Bed3D::calc_triangles(const ExPolygon& poly) { if (! m_triangles.set_from_triangles(triangulate_expolygon_2f(poly, NORMALS_UP), GROUND_Z)) @@ -320,6 +428,7 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) if (!m_gridlines.set_from_lines(gridlines, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << "Unable to create bed grid lines\n"; } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL // Try to match the print bed shape with the shape of an active profile. If such a match exists, // return the print bed model. @@ -421,6 +530,44 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) canvas.request_extra_frame(); } +#if ENABLE_GLBEGIN_GLEND_REMOVAL + init_triangles(); + + GLShaderProgram* shader = wxGetApp().get_shader("printbed"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("transparent_background", bottom); + shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg")); + + glsafe(::glEnable(GL_DEPTH_TEST)); + if (bottom) + glsafe(::glDepthMask(GL_FALSE)); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + if (bottom) + glsafe(::glFrontFace(GL_CW)); + + // show the temporary texture while no compressed data is available + GLuint tex_id = (GLuint)m_temp_texture.get_id(); + if (tex_id == 0) + tex_id = (GLuint)m_texture.get_id(); + + glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); + m_triangles.render(); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + + if (bottom) + glsafe(::glFrontFace(GL_CCW)); + + glsafe(::glDisable(GL_BLEND)); + if (bottom) + glsafe(::glDepthMask(GL_TRUE)); + + shader->stop_using(); + } +#else if (m_triangles.get_vertices_count() > 0) { GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { @@ -488,6 +635,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) shader->stop_using(); } } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } void Bed3D::render_model() @@ -541,6 +689,38 @@ void Bed3D::render_default(bool bottom, bool picking) { m_texture.reset(); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + init_gridlines(); + init_triangles(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + if (m_model.get_filename().empty() && !bottom) { + // draw background + glsafe(::glDepthMask(GL_FALSE)); + m_triangles.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR); + m_triangles.render(); + glsafe(::glDepthMask(GL_TRUE)); + } + + if (!picking) { + // draw grid + glsafe(::glLineWidth(1.5f * m_scale_factor)); + m_gridlines.set_color(picking ? DEFAULT_SOLID_GRID_COLOR : DEFAULT_TRANSPARENT_GRID_COLOR); + m_gridlines.render(); + } + + glsafe(::glDisable(GL_BLEND)); + + shader->stop_using(); + } +#else const unsigned int triangles_vcount = m_triangles.get_vertices_count(); if (triangles_vcount > 0) { const bool has_model = !m_model.get_filename().empty(); @@ -573,8 +753,10 @@ void Bed3D::render_default(bool bottom, bool picking) glsafe(::glDisable(GL_BLEND)); } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } +#if !ENABLE_GLBEGIN_GLEND_REMOVAL void Bed3D::release_VBOs() { if (m_vbo_id > 0) { @@ -582,6 +764,7 @@ void Bed3D::release_VBOs() m_vbo_id = 0; } } +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL } // GUI } // Slic3r diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 82c6b817be..350ae48f6a 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -5,7 +5,10 @@ #include "3DScene.hpp" #include "GLModel.hpp" -#include +#include "libslic3r/BuildVolume.hpp" +#if ENABLE_GLBEGIN_GLEND_REMOVAL +#include "libslic3r/ExPolygon.hpp" +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #include #include @@ -15,6 +18,7 @@ namespace GUI { class GLCanvas3D; +#if !ENABLE_GLBEGIN_GLEND_REMOVAL class GeometryBuffer { struct Vertex @@ -36,6 +40,7 @@ public: size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); } unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); } }; +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL class Bed3D { @@ -79,23 +84,38 @@ private: std::string m_model_filename; // Print volume bounding box exteded with axes and model. BoundingBoxf3 m_extended_bounding_box; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + // Print bed polygon + ExPolygon m_contour; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL // Slightly expanded print bed polygon, for collision detection. Polygon m_polygon; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLModel m_triangles; + GLModel m_gridlines; +#else GeometryBuffer m_triangles; GeometryBuffer m_gridlines; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL GLTexture m_texture; // temporary texture shown until the main texture has still no levels compressed GLTexture m_temp_texture; GLModel m_model; Vec3d m_model_offset{ Vec3d::Zero() }; +#if !ENABLE_GLBEGIN_GLEND_REMOVAL unsigned int m_vbo_id{ 0 }; +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL Axes m_axes; float m_scale_factor{ 1.0f }; public: Bed3D() = default; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + ~Bed3D() = default; +#else ~Bed3D() { release_VBOs(); } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL // Update print bed model from configuration. // Return true if the bed shape changed, so the calee will update the UI. @@ -125,8 +145,13 @@ public: private: // Calculate an extended bounding box from axes and current model for visualization purposes. BoundingBoxf3 calc_extended_bounding_box() const; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + void init_triangles(); + void init_gridlines(); +#else void calc_triangles(const ExPolygon& poly); void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL static std::tuple detect_type(const Pointfs& shape); void render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes, bool show_texture, bool picking); @@ -136,7 +161,9 @@ private: void render_model(); void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking); void render_default(bool bottom, bool picking); +#if !ENABLE_GLBEGIN_GLEND_REMOVAL void release_VBOs(); +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL }; } // GUI diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 4d3be069ca..8ac1e5534d 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -42,6 +42,16 @@ void GLModel::Geometry::add_vertex(const Vec3f& position) vertices.emplace_back(position.z()); } +void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec2f& tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P3T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec3f& normal) { assert(format.vertex_layout == EVertexLayout::P3N3); @@ -228,6 +238,7 @@ size_t GLModel::Geometry::vertex_stride_floats(const Format& format) case EVertexLayout::P2: { return 2; } case EVertexLayout::P2T2: { return 4; } case EVertexLayout::P3: { return 3; } + case EVertexLayout::P3T2: { return 5; } case EVertexLayout::P3N3: { return 6; } default: { assert(false); return 0; } }; @@ -240,6 +251,7 @@ size_t GLModel::Geometry::position_stride_floats(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: { return 2; } case EVertexLayout::P3: + case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return 3; } default: { assert(false); return 0; } }; @@ -252,6 +264,7 @@ size_t GLModel::Geometry::position_offset_floats(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: case EVertexLayout::P3: + case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return 0; } default: { assert(false); return 0; } }; @@ -279,7 +292,8 @@ size_t GLModel::Geometry::tex_coord_stride_floats(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P2T2: + case EVertexLayout::P3T2: { return 2; } default: { assert(false); return 0; } }; } @@ -289,6 +303,7 @@ size_t GLModel::Geometry::tex_coord_offset_floats(const Format& format) switch (format.vertex_layout) { case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P3T2: { return 3; } default: { assert(false); return 0; } }; } @@ -310,6 +325,7 @@ bool GLModel::Geometry::has_position(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: case EVertexLayout::P3: + case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return true; } default: { assert(false); return false; } }; @@ -321,7 +337,8 @@ bool GLModel::Geometry::has_normal(const Format& format) { case EVertexLayout::P2: case EVertexLayout::P2T2: - case EVertexLayout::P3: { return false; } + case EVertexLayout::P3: + case EVertexLayout::P3T2: { return false; } case EVertexLayout::P3N3: { return true; } default: { assert(false); return false; } }; @@ -331,7 +348,8 @@ bool GLModel::Geometry::has_tex_coord(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P2T2: { return true; } + case EVertexLayout::P2T2: + case EVertexLayout::P3T2: { return true; } case EVertexLayout::P2: case EVertexLayout::P3: case EVertexLayout::P3N3: { return false; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 61456f3773..c02f5186ca 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -58,6 +58,7 @@ namespace GUI { P2, // position 2 floats P2T2, // position 2 floats + texture coords 2 floats P3, // position 3 floats + P3T2, // position 3 floats + texture coords 2 floats P3N3, // position 3 floats + normal 3 floats }; @@ -82,6 +83,7 @@ namespace GUI { void add_vertex(const Vec2f& position); void add_vertex(const Vec2f& position, const Vec2f& tex_coord); void add_vertex(const Vec3f& position); + void add_vertex(const Vec3f& position, const Vec2f& tex_coord); void add_vertex(const Vec3f& position, const Vec3f& normal); void add_ushort_index(unsigned short id); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a33742d149..b55ba0d75e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -871,8 +871,8 @@ void GUI_App::init_app_config() { // Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release. // SetAppName(SLIC3R_APP_KEY); -// SetAppName(SLIC3R_APP_KEY "-alpha"); - SetAppName(SLIC3R_APP_KEY "-beta"); + SetAppName(SLIC3R_APP_KEY "-alpha"); +// SetAppName(SLIC3R_APP_KEY "-beta"); // SetAppDisplayName(SLIC3R_APP_NAME); // Set the Slic3r data directory at the Slic3r XS module. diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index acdbd249c4..35d68e52e5 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -95,9 +95,9 @@ wxButton* MsgDialog::get_button(wxWindowID btn_id){ void MsgDialog::apply_style(long style) { if (style & wxOK) add_button(wxID_OK, true); - if (style & wxYES) add_button(wxID_YES, true); - if (style & wxNO) add_button(wxID_NO); - if (style & wxCANCEL) add_button(wxID_CANCEL); + if (style & wxYES) add_button(wxID_YES, !(style & wxNO_DEFAULT)); + if (style & wxNO) add_button(wxID_NO, (style & wxNO_DEFAULT)); + if (style & wxCANCEL) add_button(wxID_CANCEL, (style & wxCANCEL_DEFAULT)); logo->SetBitmap( create_scaled_bitmap(style & wxICON_WARNING ? "exclamation" : style & wxICON_INFORMATION ? "info" : @@ -299,25 +299,12 @@ wxString get_wraped_wxString(const wxString& in, size_t line_len /*=80*/) for (size_t i = 0; i < in.size();) { // Overwrite the character (space or newline) starting at ibreak? bool overwrite = false; -#if wxUSE_UNICODE_WCHAR - // On Windows, most likely the internal representation of wxString is wide char. - size_t end = std::min(in.size(), i + line_len); - size_t ibreak = end; - for (size_t j = i; j < end; ++ j) { - if (bool newline = in[j] == '\n'; in[j] == ' ' || in[j] == '\t' || newline) { - ibreak = j; - overwrite = true; - if (newline) - break; - } else if (in[j] == '/' || in[j] == '\\') - ibreak = j + 1; - } -#else // UTF8 representation of wxString. // Where to break the line, index of character at the start of a UTF-8 sequence. size_t ibreak = size_t(-1); // Overwrite the character at ibreak (it is a whitespace) or not? - for (size_t cnt = 0, j = i; j < in.size();) { + size_t j = i; + for (size_t cnt = 0; j < in.size();) { if (bool newline = in[j] == '\n'; in[j] == ' ' || in[j] == '\t' || newline) { // Overwrite the whitespace. ibreak = j ++; @@ -326,16 +313,23 @@ wxString get_wraped_wxString(const wxString& in, size_t line_len /*=80*/) break; } else if (in[j] == '/') { // Insert after the slash. - ibreak = ++ j; + ibreak = ++ j; + overwrite = false; } else j += get_utf8_sequence_length(in.c_str() + j, in.size() - j); if (++ cnt == line_len) { - if (ibreak == size_t(-1)) - ibreak = j; + if (ibreak == size_t(-1)) { + ibreak = j; + overwrite = false; + } break; } } -#endif + if (j == in.size()) { + out.append(in.begin() + i, in.end()); + break; + } + assert(ibreak != size_t(-1)); out.append(in.begin() + i, in.begin() + ibreak); out.append('\n'); i = ibreak; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index a20bdb8310..b97b6cc39c 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4112,7 +4112,10 @@ wxSizer* TabPrint::create_manage_substitution_widget(wxWindow* parent) }); create_btn(&m_del_all_substitutions_btn, _L("Delete all"), "cross"); - m_del_all_substitutions_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) { + m_del_all_substitutions_btn->Bind(wxEVT_BUTTON, [this, parent](wxCommandEvent e) { + if (MessageDialog(parent, _L("Are you sure you want to delete all substitutions?"), SLIC3R_APP_NAME, wxYES_NO | wxICON_QUESTION). + ShowModal() != wxID_YES) + return; m_subst_manager.delete_all(); m_del_all_substitutions_btn->Hide(); }); diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index c62977bbaf..b3b0c15b49 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -656,6 +656,7 @@ void DiffViewCtrl::Clear() { model->Clear(); m_items_map.clear(); + m_has_long_strings = false; } wxString DiffViewCtrl::get_short_string(wxString full_string) @@ -1523,8 +1524,8 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) topSizer->Add(m_top_info_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 2 * border); topSizer->Add(presets_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); topSizer->Add(m_show_all_presets, 0, wxEXPAND | wxALL, border); - topSizer->Add(m_bottom_info_line, 0, wxEXPAND | wxALL, 2 * border); topSizer->Add(m_tree, 1, wxEXPAND | wxALL, border); + topSizer->Add(m_bottom_info_line, 0, wxEXPAND | wxALL, 2 * border); this->SetMinSize(wxSize(80 * em, 30 * em)); this->SetSizer(topSizer); @@ -1689,12 +1690,17 @@ void DiffPresetDialog::update_tree() left_val, right_val, category_icon_map.at(option.category)); } } + + if (m_tree->has_long_strings()) + bottom_info = _L("Some fields are too long to fit. Right mouse click reveals the full text."); bool tree_was_shown = m_tree->IsShown(); m_tree->Show(show_tree); - if (!show_tree) + + bool show_bottom_info = !show_tree || m_tree->has_long_strings(); + if (show_bottom_info) m_bottom_info_line->SetLabel(bottom_info); - m_bottom_info_line->Show(!show_tree); + m_bottom_info_line->Show(show_bottom_info); if (tree_was_shown == m_tree->IsShown()) Layout(); diff --git a/version.inc b/version.inc index b976d7d674..93b3763239 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer") -set(SLIC3R_VERSION "2.4.1-beta1") +set(SLIC3R_VERSION "2.5.0-alpha0") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") -set(SLIC3R_RC_VERSION "2,4,1,0") -set(SLIC3R_RC_VERSION_DOTS "2.4.1.0") +set(SLIC3R_RC_VERSION "2,5,0,0") +set(SLIC3R_RC_VERSION_DOTS "2.5.0.0") diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 962e2e04d9..cfadaf8785 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -208,5 +208,36 @@ if (MSVC) else () set(PERL_PROVE "${PERL_BIN_PATH}/prove") endif () -add_test (NAME xs COMMAND "${PERL_EXECUTABLE}" ${PERL_PROVE} -I ${PERL_LOCAL_LIB_DIR}/lib/perl5 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) -add_test (NAME integration COMMAND "${PERL_EXECUTABLE}" ${PERL_PROVE} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/..) + +set(PERL_ENV_VARS "") +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + if (SLIC3R_ASAN OR SLIC3R_UBSAN) + set(PERL_ENV_VARS env) + endif () + + if (SLIC3R_ASAN) + # Find the location of libasan.so for passing it into LD_PRELOAD. It works with GCC and Clang on Linux. + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libasan.so OUTPUT_VARIABLE LIBASAN_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + set(PERL_ENV_VARS ${PERL_ENV_VARS} "LD_PRELOAD=${LIBASAN_PATH}") + + # Suppressed memory leak reports that come from Perl. + set(PERL_LEAK_SUPPRESSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/leak_suppression.txt) + file(WRITE ${PERL_LEAK_SUPPRESSION_FILE} + "leak:Perl_safesysmalloc\n" + "leak:Perl_safesyscalloc\n" + "leak:Perl_safesysrealloc\n" + "leak:__newlocale\n") + + # Suppress a few memory leak reports and disable informing about suppressions. + # Print reports about memory leaks but exit with zero exit code when any memory leaks is found to make unit tests pass. + set(PERL_ENV_VARS ${PERL_ENV_VARS} "LSAN_OPTIONS=suppressions=${PERL_LEAK_SUPPRESSION_FILE}:print_suppressions=0:exitcode=0") + endif () + + if (SLIC3R_UBSAN) + # Do not show full stacktrace for reports from UndefinedBehaviorSanitizer in Perl tests. + set(PERL_ENV_VARS ${PERL_ENV_VARS} "UBSAN_OPTIONS=print_stacktrace=0") + endif () +endif () + +add_test (NAME xs COMMAND ${PERL_ENV_VARS} "${PERL_EXECUTABLE}" ${PERL_PROVE} -I ${PERL_LOCAL_LIB_DIR}/lib/perl5 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) +add_test (NAME integration COMMAND ${PERL_ENV_VARS} "${PERL_EXECUTABLE}" ${PERL_PROVE} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/..)