diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 2730854ebc..1ca6735cc3 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -12,8 +12,8 @@ endif() prusaslicer_add_cmake_project(wxWidgets # GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" # GIT_TAG tm_cross_compile #${_wx_git_tag} - URL https://github.com/prusa3d/wxWidgets/archive/73f029adfcc82fb3aa4b01220a013f716e57d110.zip - URL_HASH SHA256=c35fe0187db497b6a3f477e24ed5e307028657ff0c2554385810b6e7961ad2e4 + URL https://github.com/prusa3d/wxWidgets/archive/489f6118256853cf5b299d595868641938566cdb.zip + URL_HASH SHA256=5b22d465377cedd8044bba69bea958b248953fd3628c1de4913a84d4e6f6175b DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG CMAKE_ARGS -DwxBUILD_PRECOMP=ON diff --git a/resources/icons/legend_cog.svg b/resources/icons/legend_cog.svg new file mode 100644 index 0000000000..9a55fb7f5c --- /dev/null +++ b/resources/icons/legend_cog.svg @@ -0,0 +1,50 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/resources/profiles/Anycubic.ini b/resources/profiles/Anycubic.ini index 053aecbd59..a67ba0962f 100644 --- a/resources/profiles/Anycubic.ini +++ b/resources/profiles/Anycubic.ini @@ -64,6 +64,13 @@ technology = FFF family = PREDATOR default_materials = Generic PLA @PREDATOR; Generic PETG @PREDATOR; Generic ABS @PREDATOR +[printer_model:PHOTON MONO X] +name = Photon Mono X +variants = default +technology = SLA +family = PHOTON MONO +default_materials = Generic Blue Resin MONO @0.05 + # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -1898,3 +1905,96 @@ default_print_profile = 0.24mm 0.8 nozzle DETAILED QUALITY @PREDATOR ######################################### ########## end printer presets ########## ######################################### + +######################################### +########## SLA printer presets ########## +######################################### + + +[sla_print:*common print ANYCUBIC SLA*] +compatible_printers_condition = family=="PHOTON MONO" +layer_height = 0.05 +output_filename_format = [input_filename_base].pwmx +pad_edge_radius = 0.5 +pad_enable = 0 +pad_max_merge_distance = 50 +pad_wall_height = 0 +pad_wall_thickness = 1 +pad_wall_slope = 45 +faded_layers = 8 +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_critical_angle = 45 +support_density_at_45 = 250 +support_density_at_horizontal = 500 +support_head_front_diameter = 0.4 +support_head_penetration = 0.4 +support_head_width = 3 +support_max_bridge_length = 10 +support_minimal_z = 0 +support_object_elevation = 5 +support_pillar_diameter = 1 +support_pillar_connection_mode = zigzag +support_pillar_widening_factor = 0 +supports_enable = 1 +support_small_pillar_diameter_percent = 60% + +[sla_print:0.05 ANYCUBIC SLA] +inherits = *common print ANYCUBIC SLA* +layer_height = 0.05 + + +########### Materials + +[sla_material:*common ANYCUBIC SLA*] +compatible_printers_condition = family=="PHOTON MONO" +compatible_prints_condition = layer_height == 0.05 +exposure_time = 7 +initial_exposure_time = 40 +initial_layer_height = 0.05 +material_correction = 1,1,1 +material_notes = LIFT_DISTANCE=8.0\nLIFT_SPEED=2.5\nRETRACT_SPEED=3.0\nBOTTOM_LIFT_SPEED=2.0\nBOTTOM_LIFT_DISTANCE=9.0\nDELAY_BEFORE_EXPOSURE=0.5 + +[sla_material:*common 0.05 ANYCUBIC SLA*] +inherits = *common ANYCUBIC SLA* + +[sla_material:Generic Blue Resin MONO @0.05] +inherits = *common 0.05 ANYCUBIC SLA* +exposure_time = 2.5 +initial_exposure_time = 40 +material_type = Tough +material_vendor = Generic +material_colour = #6080EC + +########## Printers + +[printer:Anycubic Photon Mono X] +printer_technology = SLA +printer_model = PHOTON MONO X +printer_variant = default +default_sla_material_profile = Generic Blue Resin MONO @0.05 +default_sla_print_profile = 0.05 ANYCUBIC SLA +thumbnails = 224x168 +sla_archive_format = pwmx +bed_shape = 1.48x1.02,193.48x1.02,193.48x121.02,1.48x121.02 +display_height = 120 +display_orientation = landscape +display_mirror_x = 1 +display_mirror_y = 0 +display_pixels_x = 3840 +display_pixels_y = 2400 +display_width = 192 +max_print_height = 245 +elefant_foot_compensation = 0.2 +elefant_foot_min_width = 0.2 +min_exposure_time = 1 +max_exposure_time = 120 +min_initial_exposure_time = 1 +max_initial_exposure_time = 300 +printer_correction = 1,1,1 +gamma_correction = 1 +area_fill = 45 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.'\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTONMONOX\n + + diff --git a/resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png b/resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png new file mode 100644 index 0000000000..70ad47b63d Binary files /dev/null and b/resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png differ diff --git a/resources/shaders/toolpaths_cog.fs b/resources/shaders/toolpaths_cog.fs new file mode 100644 index 0000000000..f88d79b969 --- /dev/null +++ b/resources/shaders/toolpaths_cog.fs @@ -0,0 +1,18 @@ +#version 110 + +const vec4 BLACK = vec4(vec3(0.1), 1.0); +const vec4 WHITE = vec4(vec3(1.0), 1.0); + +const float emission_factor = 0.25; + +// x = tainted, y = specular; +varying vec2 intensity; +varying vec3 world_position; +uniform vec3 world_center; + +void main() +{ + vec3 delta = world_position - world_center; + vec4 color = delta.x * delta.y * delta.z > 0.0 ? BLACK : WHITE; + gl_FragColor = vec4(vec3(intensity.y) + color.rgb * (intensity.x + emission_factor), 1.0); +} diff --git a/resources/shaders/toolpaths_cog.vs b/resources/shaders/toolpaths_cog.vs new file mode 100644 index 0000000000..c7b1abfdbd --- /dev/null +++ b/resources/shaders/toolpaths_cog.vs @@ -0,0 +1,40 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +// x = tainted, y = specular; +varying vec2 intensity; +varying vec3 world_position; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + world_position = gl_Vertex.xyz; + gl_Position = ftransform(); +} diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index db0e54e60d..f2c3ef0837 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -165,8 +165,9 @@ namespace ImGui const wchar_t LegendColorChanges = 0x2612; const wchar_t LegendPausePrints = 0x2613; const wchar_t LegendCustomGCodes = 0x2614; - const wchar_t LegendShells = 0x2615; - const wchar_t LegendToolMarker = 0x2616; + const wchar_t LegendCOG = 0x2615; + const wchar_t LegendShells = 0x2616; + const wchar_t LegendToolMarker = 0x2617; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d4c8d7edc1..ea663f2e1f 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -98,6 +98,8 @@ set(SLIC3R_SOURCES Format/SL1.cpp Format/SL1_SVG.hpp Format/SL1_SVG.cpp + Format/pwmx.hpp + Format/pwmx.cpp GCode/ThumbnailData.cpp GCode/ThumbnailData.hpp GCode/Thumbnails.cpp diff --git a/src/libslic3r/Format/pwmx.cpp b/src/libslic3r/Format/pwmx.cpp new file mode 100644 index 0000000000..99785b8d08 --- /dev/null +++ b/src/libslic3r/Format/pwmx.cpp @@ -0,0 +1,509 @@ +#include "pwmx.hpp" +#include "GCode/ThumbnailData.hpp" + +#include +#include +#include + + +#define TAG_INTRO "ANYCUBIC\0\0\0\0" +#define TAG_HEADER "HEADER\0\0\0\0\0\0" +#define TAG_PREVIEW "PREVIEW\0\0\0\0\0" +#define TAG_LAYERS "LAYERDEF\0\0\0\0" + +#define CFG_LIFT_DISTANCE "LIFT_DISTANCE" +#define CFG_LIFT_SPEED "LIFT_SPEED" +#define CFG_RETRACT_SPEED "RETRACT_SPEED" +#define CFG_DELAY_BEFORE_EXPOSURE "DELAY_BEFORE_EXPOSURE" +#define CFG_BOTTOM_LIFT_SPEED "BOTTOM_LIFT_SPEED" +#define CFG_BOTTOM_LIFT_DISTANCE "BOTTOM_LIFT_DISTANCE" + +#define PREV_W 224 +#define PREV_H 168 +#define PREV_DPI 42 + +#define LAYER_SIZE_ESTIMATE (32 * 1024) + + +namespace Slic3r { + +using ConfMap = std::map; + +typedef struct pwmx_format_intro +{ + char tag[12]; + std::uint32_t version; // value 1 + std::uint32_t area_num; // unknown - usually 4 + std::uint32_t header_data_offset; + std::float_t intro24; // unknown - usually 0 + std::uint32_t preview_data_offset; + std::float_t intro32; // unknown + std::uint32_t layer_data_offset; + std::float_t intro40; // unknown + std::uint32_t image_data_offset; +} pwmx_format_intro; + +typedef struct pwmx_format_header +{ + char tag[12]; + std::uint32_t payload_size; + std::float_t pixel_size_um; + std::float_t layer_height_mm; + std::float_t exposure_time_s; + std::float_t delay_before_exposure_s; + std::float_t bottom_exposure_time_s; + std::float_t bottom_layer_count; + std::float_t lift_distance_mm; + std::float_t lift_speed_mms; + std::float_t retract_speed_mms; + std::float_t volume_ml; + std::uint32_t antialiasing; + std::uint32_t res_x; + std::uint32_t res_y; + std::float_t weight_g; + std::float_t price; + std::uint32_t price_currency; + std::uint32_t per_layer_override; // ? unknown meaning ? + std::uint32_t print_time_s; + std::uint32_t transition_layer_count; + std::uint32_t unknown; // ? usually 0 ? + +} pwmx_format_header; + +typedef struct pwmx_format_preview +{ + char tag[12]; + std::uint32_t payload_size; + std::uint32_t preview_w; + std::uint32_t preview_dpi; + std::uint32_t preview_h; + // raw image data in BGR565 format + std::uint8_t pixels[PREV_W * PREV_H * 2]; +} pwmx_format_preview; + +typedef struct pwmx_format_layers_header +{ + char tag[12]; + std::uint32_t payload_size; + std::uint32_t layer_count; +} pwmx_format_layers_header; + +typedef struct pwmx_format_layer +{ + std::uint32_t image_offset; + std::uint32_t image_size; + std::float_t lift_distance_mm; + std::float_t lift_speed_mms; + std::float_t exposure_time_s; + std::float_t layer_height_mm; + std::float_t layer44; // unkown - usually 0 + std::float_t layer48; // unkown - usually 0 +} pwmx_format_layer; + +typedef struct pwmx_format_misc +{ + std::float_t bottom_layer_height_mm; + std::float_t bottom_lift_distance_mm; + std::float_t bottom_lift_speed_mms; + +} pwmx_format_misc; + +class PwmxFormatConfigDef : public ConfigDef +{ +public: + PwmxFormatConfigDef() + { + add(CFG_LIFT_DISTANCE, coFloat); + add(CFG_LIFT_SPEED, coFloat); + add(CFG_RETRACT_SPEED, coFloat); + add(CFG_DELAY_BEFORE_EXPOSURE, coFloat); + add(CFG_BOTTOM_LIFT_DISTANCE, coFloat); + add(CFG_BOTTOM_LIFT_SPEED, coFloat); + } +}; + +class PwmxFormatDynamicConfig : public DynamicConfig +{ +public: + PwmxFormatDynamicConfig(){}; + const ConfigDef *def() const override { return &config_def; } + +private: + PwmxFormatConfigDef config_def; +}; + +namespace { + +const char *get_cfg_value(const DynamicConfig &cfg, + const std::string & key, + const std::string & def = "0") +{ + std::string ret; + + if (cfg.has(key)) { + auto opt = cfg.option(key); + if (opt) { + ret = opt->serialize(); + } else { + return def.c_str(); + } + } else { + return def.c_str(); + } + + return ret.c_str(); +} + +template void crop_value(T &val, T val_min, T val_max) +{ + if (val < val_min) { + val = val_min; + } else if (val > val_max) { + val = val_max; + } +} + +void fill_preview(pwmx_format_preview &p, + pwmx_format_misc &m, + ThumbnailsList &thumbnails) +{ + + p.preview_w = PREV_W; + p.preview_h = PREV_H; + p.preview_dpi = PREV_DPI; + p.payload_size = sizeof(p) - sizeof(p.tag) - sizeof(p.payload_size); + + std::memset(p.pixels, 0 , sizeof(p.pixels)); + if (!thumbnails.empty()) { + std::uint32_t dst_index; + std::uint32_t i = 0; + size_t len; + size_t pixel_x = 0; + auto t = thumbnails[0]; //use the first thumbnail + len = t.pixels.size(); + //sanity check + if (len != PREV_W * PREV_H * 4) { + printf("incorrect thumbnail size. expected %ix%i\n", PREV_W, PREV_H); + return; + } + // rearange pixels: they seem to be stored from bottom to top. + dst_index = (PREV_W * (PREV_H - 1) * 2); + while (i < len) { + std::uint32_t pixel; + std::uint32_t r = t.pixels[i++]; + std::uint32_t g = t.pixels[i++]; + std::uint32_t b = t.pixels[i++]; + i++; // Alpha + // convert to BGRA565 + pixel = ((b >> 3) << 11) | ((g >>2) << 5) | (r >> 3); + p.pixels[dst_index++] = pixel & 0xFF; + p.pixels[dst_index++] = (pixel >> 8) & 0xFF; + pixel_x++; + if (pixel_x == PREV_W) { + pixel_x = 0; + dst_index -= (PREV_W * 4); + } + } + } +} + + +void fill_header(pwmx_format_header &h, + pwmx_format_misc &m, + const SLAPrint &print, + std::uint32_t layer_count) +{ + std::float_t bottle_weight_g; + std::float_t bottle_volume_ml; + std::float_t bottle_cost; + std::float_t material_density; + auto & cfg = print.full_print_config(); + std::string mnotes = cfg.option("material_notes")->serialize(); + // create a config parser from the material notes + Slic3r::PwmxFormatDynamicConfig mat_cfg; + SLAPrintStatistics stats = print.print_statistics(); + + // sanitize the string config + boost::replace_all(mnotes, "\\n", "\n"); + boost::replace_all(mnotes, "\\r", "\r"); + mat_cfg.load_from_ini_string(mnotes, + ForwardCompatibilitySubstitutionRule::Enable); + + h.layer_height_mm = std::atof(get_cfg_value(cfg, "layer_height")); + m.bottom_layer_height_mm = std::atof( + get_cfg_value(cfg, "initial_layer_height")); + h.exposure_time_s = std::atof(get_cfg_value(cfg, "exposure_time")); + h.bottom_exposure_time_s = std::atof( + get_cfg_value(cfg, "initial_exposure_time")); + h.bottom_layer_count = std::atof(get_cfg_value(cfg, "faded_layers")); + if (layer_count < h.bottom_layer_count) { + h.bottom_layer_count = layer_count; + } + h.res_x = std::atol(get_cfg_value(cfg, "display_pixels_x")); + h.res_y = std::atol(get_cfg_value(cfg, "display_pixels_y")); + bottle_weight_g = std::atof(get_cfg_value(cfg, "bottle_weight")) * 1000.0f; + bottle_volume_ml = std::atof(get_cfg_value(cfg, "bottle_volume")); + bottle_cost = std::atof(get_cfg_value(cfg, "bottle_cost")); + material_density = bottle_weight_g / bottle_volume_ml; + + h.volume_ml = (stats.objects_used_material + stats.support_used_material) / 1000; + h.weight_g = h.volume_ml * material_density; + h.price = (h.volume_ml * bottle_cost) / bottle_volume_ml; + h.price_currency = '$'; + h.antialiasing = 1; + h.per_layer_override = 0; + + // TODO - expose these variables to the UI rather than using material notes + h.delay_before_exposure_s = std::atof( + get_cfg_value(mat_cfg, CFG_DELAY_BEFORE_EXPOSURE, "0.5")); + crop_value(h.delay_before_exposure_s, 0.0f, 1000.0f); + + h.lift_distance_mm = std::atof( + get_cfg_value(mat_cfg, CFG_LIFT_DISTANCE, "8.0")); + crop_value(h.lift_distance_mm, 0.0f, 100.0f); + + if (mat_cfg.has(CFG_BOTTOM_LIFT_DISTANCE)) { + m.bottom_lift_distance_mm = std::atof( + get_cfg_value(mat_cfg, CFG_BOTTOM_LIFT_DISTANCE, "8.0")); + crop_value(h.lift_distance_mm, 0.0f, 100.0f); + } else { + m.bottom_lift_distance_mm = h.lift_distance_mm; + } + + + h.lift_speed_mms = std::atof( + get_cfg_value(mat_cfg, CFG_LIFT_SPEED, "2.0")); + crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f); + + if (mat_cfg.has(CFG_BOTTOM_LIFT_SPEED)) { + m.bottom_lift_speed_mms = std::atof( + get_cfg_value(mat_cfg, CFG_BOTTOM_LIFT_SPEED, "2.0")); + crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f); + } else { + m.bottom_lift_speed_mms = h.lift_speed_mms; + } + + h.retract_speed_mms = std::atof( + get_cfg_value(mat_cfg, CFG_RETRACT_SPEED, "3.0")); + crop_value(h.lift_speed_mms, 0.1f, 20.0f); + + h.print_time_s = (h.bottom_layer_count * h.bottom_exposure_time_s) + + ((layer_count - h.bottom_layer_count) * + h.exposure_time_s) + + (layer_count * h.lift_distance_mm / h.retract_speed_mms) + + (layer_count * h.lift_distance_mm / h.lift_speed_mms) + + (layer_count * h.delay_before_exposure_s); + + + h.payload_size = sizeof(h) - sizeof(h.tag) - sizeof(h.payload_size); + h.pixel_size_um = 50; +} + +} // namespace + +std::unique_ptr PwmxArchive::create_raster() const +{ + sla::Resolution res; + sla::PixelDim pxdim; + std::array mirror; + + double w = m_cfg.display_width.getFloat(); + double h = m_cfg.display_height.getFloat(); + auto pw = size_t(m_cfg.display_pixels_x.getInt()); + auto ph = size_t(m_cfg.display_pixels_y.getInt()); + + mirror[X] = m_cfg.display_mirror_x.getBool(); + mirror[Y] = m_cfg.display_mirror_y.getBool(); + + auto ro = m_cfg.display_orientation.getInt(); + sla::RasterBase::Orientation orientation = + ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait : + sla::RasterBase::roLandscape; + + if (orientation == sla::RasterBase::roPortrait) { + std::swap(w, h); + std::swap(pw, ph); + } + + res = sla::Resolution{pw, ph}; + pxdim = sla::PixelDim{w / pw, h / ph}; + sla::RasterBase::Trafo tr{orientation, mirror}; + + double gamma = m_cfg.gamma_correction.getFloat(); + + return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr); +} + +sla::RasterEncoder PwmxArchive::get_encoder() const +{ + return sla::PWXRasterEncoder{}; +} + +// Endian safe write of little endian 32bit ints +static void pwmx_write_int32(std::ofstream &out, std::uint32_t val) +{ + const char i1 = (val & 0xFF); + const char i2 = (val >> 8) & 0xFF; + const char i3 = (val >> 16) & 0xFF; + const char i4 = (val >> 24) & 0xFF; + + out.write((const char *) &i1, 1); + out.write((const char *) &i2, 1); + out.write((const char *) &i3, 1); + out.write((const char *) &i4, 1); +} +static void pwmx_write_float(std::ofstream &out, std::float_t val) +{ + std::uint32_t *f = (std::uint32_t *) &val; + pwmx_write_int32(out, *f); +} + +static void pwmx_write_intro(std::ofstream &out, pwmx_format_intro &i) +{ + out.write(TAG_INTRO, sizeof(i.tag)); + pwmx_write_int32(out, i.version); + pwmx_write_int32(out, i.area_num); + pwmx_write_int32(out, i.header_data_offset); + pwmx_write_int32(out, i.intro24); + pwmx_write_int32(out, i.preview_data_offset); + pwmx_write_int32(out, i.intro32); + pwmx_write_int32(out, i.layer_data_offset); + pwmx_write_int32(out, i.intro40); + pwmx_write_int32(out, i.image_data_offset); +} + +static void pwmx_write_header(std::ofstream &out, pwmx_format_header &h) +{ + out.write(TAG_HEADER, sizeof(h.tag)); + pwmx_write_int32(out, h.payload_size); + pwmx_write_float(out, h.pixel_size_um); + pwmx_write_float(out, h.layer_height_mm); + pwmx_write_float(out, h.exposure_time_s); + pwmx_write_float(out, h.delay_before_exposure_s); + pwmx_write_float(out, h.bottom_exposure_time_s); + pwmx_write_float(out, h.bottom_layer_count); + pwmx_write_float(out, h.lift_distance_mm); + pwmx_write_float(out, h.lift_speed_mms); + pwmx_write_float(out, h.retract_speed_mms); + pwmx_write_float(out, h.volume_ml); + pwmx_write_int32(out, h.antialiasing); + pwmx_write_int32(out, h.res_x); + pwmx_write_int32(out, h.res_y); + pwmx_write_float(out, h.weight_g); + pwmx_write_float(out, h.price); + pwmx_write_int32(out, h.price_currency); + pwmx_write_int32(out, h.per_layer_override); + pwmx_write_int32(out, h.print_time_s); + pwmx_write_int32(out, h.transition_layer_count); + pwmx_write_int32(out, h.unknown); +} + +static void pwmx_write_preview(std::ofstream &out, pwmx_format_preview &p) +{ + out.write(TAG_PREVIEW, sizeof(p.tag)); + pwmx_write_int32(out, p.payload_size); + pwmx_write_int32(out, p.preview_w); + pwmx_write_int32(out, p.preview_dpi); + pwmx_write_int32(out, p.preview_h); + out.write((const char*) p.pixels, sizeof(p.pixels)); +} + +static void pwmx_write_layers_header(std::ofstream &out, pwmx_format_layers_header &h) +{ + out.write(TAG_LAYERS, sizeof(h.tag)); + pwmx_write_int32(out, h.payload_size); + pwmx_write_int32(out, h.layer_count); +} + +static void pwmx_write_layer(std::ofstream &out, pwmx_format_layer &l) +{ + pwmx_write_int32(out, l.image_offset); + pwmx_write_int32(out, l.image_size); + pwmx_write_float(out, l.lift_distance_mm); + pwmx_write_float(out, l.lift_speed_mms); + pwmx_write_float(out, l.exposure_time_s); + pwmx_write_float(out, l.layer_height_mm); + pwmx_write_float(out, l.layer44); + pwmx_write_float(out, l.layer48); +} + +void PwmxArchive::export_print(const std::string fname, + const SLAPrint & print, + ThumbnailsList & thumbnails, + const std::string &prjname) +{ + std::uint32_t layer_count = m_layers.size(); + + pwmx_format_intro intro = {0}; + pwmx_format_header header = {0}; + pwmx_format_preview preview = {0}; + pwmx_format_layers_header layers_header = {0}; + pwmx_format_misc misc = {0}; + std::vector layer_images; + std::uint32_t image_offset; + + intro.version = 1; + intro.area_num = 4; + intro.header_data_offset = sizeof(intro); + intro.preview_data_offset = sizeof(intro) + sizeof(header); + intro.layer_data_offset = intro.preview_data_offset + sizeof(preview); + intro.image_data_offset = intro.layer_data_offset + + sizeof(layers_header) + + (sizeof(pwmx_format_layer) * layer_count); + + fill_header(header, misc, print, layer_count); + fill_preview(preview, misc, thumbnails); + + try { + // open the file and write the contents + std::ofstream out; + out.open(fname, std::ios::binary | std::ios::out | std::ios::trunc); + pwmx_write_intro(out, intro); + pwmx_write_header(out, header); + pwmx_write_preview(out, preview); + + layers_header.payload_size = intro.image_data_offset - intro.layer_data_offset - + sizeof(layers_header.tag) - sizeof(layers_header.payload_size); + layers_header.layer_count = layer_count; + pwmx_write_layers_header(out, layers_header); + + //layers + layer_images.reserve(layer_count * LAYER_SIZE_ESTIMATE); + image_offset = intro.image_data_offset; + size_t i = 0; + for (const sla::EncodedRaster &rst : m_layers) { + pwmx_format_layer l; + std::memset(&l, 0, sizeof(l)); + l.image_offset = image_offset; + l.image_size = rst.size(); + if (i < header.bottom_layer_count) { + l.exposure_time_s = header.bottom_exposure_time_s; + l.layer_height_mm = misc.bottom_layer_height_mm; + l.lift_distance_mm = misc.bottom_lift_distance_mm; + l.lift_speed_mms = misc.bottom_lift_speed_mms; + } else { + l.exposure_time_s = header.exposure_time_s; + l.layer_height_mm = header.layer_height_mm; + l.lift_distance_mm = header.lift_distance_mm; + l.lift_speed_mms = header.lift_speed_mms; + } + image_offset += l.image_size; + pwmx_write_layer(out, l); + // add the rle encoded layer image into the buffer + const char* img_start = reinterpret_cast(rst.data()); + const char* img_end = img_start + rst.size(); + std::copy(img_start, img_end, std::back_inserter(layer_images)); + i++; + } + const char* img_buffer = reinterpret_cast(layer_images.data()); + out.write(img_buffer, layer_images.size()); + out.close(); + } catch(std::exception& e) { + BOOST_LOG_TRIVIAL(error) << e.what(); + // Rethrow the exception + throw; + } + +} + +} // namespace Slic3r diff --git a/src/libslic3r/Format/pwmx.hpp b/src/libslic3r/Format/pwmx.hpp new file mode 100644 index 0000000000..69cec100c3 --- /dev/null +++ b/src/libslic3r/Format/pwmx.hpp @@ -0,0 +1,36 @@ +#ifndef _SLIC3R_FORMAT_PWMX_HPP_ +#define _SLIC3R_FORMAT_PWMX_HPP_ + +#include + +#include "libslic3r/SLAPrint.hpp" + +namespace Slic3r { + +class PwmxArchive: public SLAArchive { + SLAPrinterConfig m_cfg; + +protected: + std::unique_ptr create_raster() const override; + sla::RasterEncoder get_encoder() const override; + + SLAPrinterConfig & cfg() { return m_cfg; } + const SLAPrinterConfig & cfg() const { return m_cfg; } + +public: + + PwmxArchive() = default; + explicit PwmxArchive(const SLAPrinterConfig &cfg): m_cfg(cfg) {} + explicit PwmxArchive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {} + + void export_print(const std::string fname, + const SLAPrint &print, + ThumbnailsList &thumbnails, + const std::string &projectname = "") override; + bool uses_zipper_export() override {return false;} +}; + + +} // namespace Slic3r::sla + +#endif // _SLIC3R_FORMAT_PWMX_HPP_ diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 6a53917de1..fb6dee37ba 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -174,7 +174,7 @@ namespace Slic3r { gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Start) + "\n"; auto end = this->path.points.end(); bool done = false; - for (; it != end; ++ it) { + for (; it != end && ! done; ++ it) { p = gcodegen.point_to_gcode_quantized(*it); double segment_length = (p - prev).norm(); double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 58e8ed787a..50c0ce4a54 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1196,6 +1196,7 @@ void GCodeProcessor::reset() m_line_id = 0; m_last_line_id = 0; m_feedrate = 0.0f; + m_feed_multiply.reset(); m_width = 0.0f; m_height = 0.0f; m_forced_width = 0.0f; @@ -1698,6 +1699,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool break; case '2': switch (cmd[3]) { + case '0': { process_M220(line); break; } // Set Feedrate Percentage case '1': { process_M221(line); break; } // Set extrude factor override percentage default: break; } @@ -2498,7 +2500,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) // updates feedrate from line, if present if (line.has_f()) - m_feedrate = line.f() * MMMIN_TO_MMSEC; + m_feedrate = m_feed_multiply.current * line.f() * MMMIN_TO_MMSEC; // calculates movement deltas float max_abs_delta = 0.0f; @@ -2863,7 +2865,7 @@ void GCodeProcessor::process_G61(const GCodeReader::GCodeLine& line) modified = true; } if (line.has_f()) - m_feedrate = line.f(); + m_feedrate = m_feed_multiply.current * line.f(); if (!modified) m_end_position = m_saved_position; @@ -3136,6 +3138,20 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line) } } +void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line) +{ + if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware) + return; + + if (line.has('B')) + m_feed_multiply.saved = m_feed_multiply.current; + float value; + if (line.has_value('S', value)) + m_feed_multiply.current = value * 0.01f; + if (line.has('R')) + m_feed_multiply.current = m_feed_multiply.saved; +} + void GCodeProcessor::process_M221(const GCodeReader::GCodeLine& line) { float value_s; diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 7e4bb831d8..25375f61b6 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -525,6 +525,17 @@ namespace Slic3r { unsigned int m_line_id; unsigned int m_last_line_id; float m_feedrate; // mm/s + struct FeedMultiply + { + float current; // percentage + float saved; // percentage + + void reset() { + current = 1.0f; + saved = 1.0f; + } + }; + FeedMultiply m_feed_multiply; float m_width; // mm float m_height; // mm float m_forced_width; // mm @@ -719,6 +730,9 @@ namespace Slic3r { // Advanced settings void process_M205(const GCodeReader::GCodeLine& line); + // Set Feedrate Percentage + void process_M220(const GCodeReader::GCodeLine& line); + // Set extrude factor override percentage void process_M221(const GCodeReader::GCodeLine& line); diff --git a/src/libslic3r/SLA/RasterBase.cpp b/src/libslic3r/SLA/RasterBase.cpp index 0b6c45eff3..fd3f3e062d 100644 --- a/src/libslic3r/SLA/RasterBase.cpp +++ b/src/libslic3r/SLA/RasterBase.cpp @@ -16,6 +16,54 @@ const RasterBase::TMirroring RasterBase::MirrorX = {true, false}; const RasterBase::TMirroring RasterBase::MirrorY = {false, true}; const RasterBase::TMirroring RasterBase::MirrorXY = {true, true}; + + +static void pwx_get_pixel_span(const std::uint8_t* ptr, const std::uint8_t* end, + std::uint8_t& pixel, size_t& span_len) +{ + size_t max_len; + + span_len = 0; + pixel = (*ptr) & 0xF0; + // the maximum length of the span depends on the pixel color + max_len = (pixel == 0 || pixel == 0xF0) ? 0xFFF : 0xF; + while (((*ptr) & 0xF0) == pixel && ptr < end && span_len < max_len) { + span_len++; + ptr++; + } +} + +EncodedRaster PWXRasterEncoder::operator()(const void *ptr, size_t w, size_t h, + size_t num_components) +{ + std::vector dst; + size_t span_len; + std::uint8_t pixel; + auto size = w * h * num_components; + dst.reserve(size); + + const std::uint8_t* src = reinterpret_cast(ptr); + const std::uint8_t* src_end = src + size; + while (src < src_end) { + pwx_get_pixel_span(src, src_end, pixel, span_len); + src += span_len; + // fully transparent of fully opaque pixel + if (pixel == 0 || pixel == 0xF0) { + pixel = pixel | (span_len >> 8); + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + pixel = span_len & 0xFF; + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + } + // antialiased pixel + else { + pixel = pixel | span_len; + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + } + } + + return EncodedRaster(std::move(dst), "pwx"); +} + EncodedRaster PNGRasterEncoder::operator()(const void *ptr, size_t w, size_t h, size_t num_components) { diff --git a/src/libslic3r/SLA/RasterBase.hpp b/src/libslic3r/SLA/RasterBase.hpp index 657fc865c2..9d22591cc7 100644 --- a/src/libslic3r/SLA/RasterBase.hpp +++ b/src/libslic3r/SLA/RasterBase.hpp @@ -97,6 +97,10 @@ public: virtual EncodedRaster encode(RasterEncoder encoder) const = 0; }; +struct PWXRasterEncoder { + EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components); +}; + struct PNGRasterEncoder { EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components); }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 7b78dfea2f..23502c44e3 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -3,6 +3,7 @@ #include "Format/SL1.hpp" #include "Format/SL1_SVG.hpp" +#include "Format/pwmx.hpp" #include "ClipperUtils.hpp" #include "Geometry.hpp" @@ -16,6 +17,8 @@ #include #include +#include + // #define SLAPRINT_DO_BENCHMARK #ifdef SLAPRINT_DO_BENCHMARK @@ -249,6 +252,9 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con m_archiver = std::make_unique(m_printer_config); else if (m_printer_config.sla_archive_format.value == "SL2") m_archiver = std::make_unique(m_printer_config); + else if (m_printer_config.sla_archive_format.value == "pwmx") { + m_archiver = std::make_unique(m_printer_config); + } } struct ModelObjectStatus { @@ -1265,4 +1271,16 @@ void SLAPrint::StatusReporter::operator()(SLAPrint & p, p.set_status(int(std::round(st)), msg, flags); } + +void SLAPrint::write_thumbnail(Zipper& zipper, const ThumbnailData& data) +{ + size_t png_size = 0; + void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); + if (png_data != nullptr) + { + zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size); + mz_free(png_data); + } +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index b2df0c4e92..8d5b54376a 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -9,6 +9,7 @@ #include "Point.hpp" #include "MTUtils.hpp" #include "Zipper.hpp" +#include "GCode/ThumbnailData.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" @@ -422,12 +423,16 @@ public: } // Export the print into an archive using the provided zipper. - // TODO: Use an archive writer interface instead of Zipper. - // This is quite limiting as the Zipper is a complete class, not an interface. - // The output can only be a zip archive. virtual void export_print(Zipper &zipper, const SLAPrint &print, - const std::string &projectname = "") = 0; + const std::string &projectname = "") {}; + // Export the print into an archive using the provided filename. + virtual void export_print(const std::string fname, + const SLAPrint &print, + ThumbnailsList &thumbnails, + const std::string &projectname = "") {}; + // By default the exporters use zipper export. Return false to use file export. + virtual bool uses_zipper_export() { return true; } }; /** @@ -533,16 +538,27 @@ public: // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } - - void export_print(Zipper &zipper, const std::string &projectname = "") - { - m_archiver->export_print(zipper, *this, projectname); - } + + void write_thumbnail(Zipper& zipper, const ThumbnailData& data); void export_print(const std::string &fname, const std::string &projectname = "") { - Zipper zipper(fname); - export_print(zipper, projectname); + Slic3r::ThumbnailsList thumbnails; //empty thumbnail list + export_print(fname, thumbnails, projectname); + } + + void export_print(const std::string &fname, Slic3r::ThumbnailsList &thumbnails, const std::string &projectname = "") + { + if (m_archiver->uses_zipper_export()) { + Zipper zipper(fname); + m_archiver->export_print(zipper, *this, projectname); + for (const ThumbnailData& data : thumbnails) + if (data.is_valid()) + write_thumbnail(zipper, data); + zipper.finalize(); + } else { + m_archiver->export_print(fname, *this, thumbnails, projectname); + } } private: diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index e0a8f93693..6d905617df 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -68,10 +68,16 @@ #define ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL (1 && ENABLE_2_5_0_ALPHA1) // Enable removal of old OpenGL render calls #define ENABLE_GLBEGIN_GLEND_REMOVAL (1 && ENABLE_2_5_0_ALPHA1) +// Enable replace GLIndexedVertexArray with GLModel +#define ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL (1 && ENABLE_GLBEGIN_GLEND_REMOVAL) // Enable show non-manifold edges #define ENABLE_SHOW_NON_MANIFOLD_EDGES (1 && ENABLE_2_5_0_ALPHA1) // Enable rework of Reload from disk command #define ENABLE_RELOAD_FROM_DISK_REWORK (1 && ENABLE_2_5_0_ALPHA1) +// Enable showing toolpaths center of gravity +#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1) +// Enable recalculating toolpaths when switching to/from volumetric rate visualization +#define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1) // Enable editing volumes transformation in world coordinates and instances in local coordinates #define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_5_0_ALPHA1) // Enable showing world coordinates of volumes' offset relative to the instance containing them diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c8ca2397bb..244a802dbc 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -311,10 +311,10 @@ void Bed3D::init_triangles() 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 }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, GLModel::Geometry::index_type(triangles.size()) }; + init_data.reserve_vertices(triangles.size()); + init_data.reserve_indices(triangles.size() / 3); Vec2f min = triangles.front(); Vec2f max = min; @@ -330,13 +330,14 @@ void Bed3D::init_triangles() Vec2f inv_size = size.cwiseInverse(); inv_size.y() *= -1.0f; + // vertices + indices 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()); + init_data.add_vertex(p, (Vec2f)(v - min).cwiseProduct(inv_size).eval()); ++vertices_counter; if (vertices_counter % 3 == 0) { - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.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); @@ -378,16 +379,16 @@ void Bed3D::init_gridlines() 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 }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * gridlines.size()) }; + init_data.reserve_vertices(2 * gridlines.size()); + init_data.reserve_indices(2 * gridlines.size()); 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) + if (init_data.format.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); @@ -701,7 +702,9 @@ void Bed3D::render_default(bool bottom, bool picking) glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - if (m_model.get_filename().empty() && !bottom) { + const bool has_model = !m_model.get_filename().empty(); + + if (!has_model && !bottom) { // draw background glsafe(::glDepthMask(GL_FALSE)); m_triangles.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR); @@ -712,7 +715,7 @@ void Bed3D::render_default(bool bottom, bool picking) 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.set_color(has_model && !bottom ? DEFAULT_SOLID_GRID_COLOR : DEFAULT_TRANSPARENT_GRID_COLOR); m_gridlines.render(); } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4e929d060c..23ca974dd7 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -326,8 +326,8 @@ void GLVolume::SinkingContours::update() for (const ExPolygon& expoly : diff_ex(expand(polygons, float(scale_(HalfWidth))), shrink(polygons, float(scale_(HalfWidth))))) { #if ENABLE_GLBEGIN_GLEND_REMOVAL const std::vector triangulation = triangulate_expolygon_3d(expoly); - init_data.vertices.reserve(init_data.vertices.size() + triangulation.size() * GUI::GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(init_data.indices.size() + triangulation.size() * GUI::GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(init_data.vertices_count() + triangulation.size()); + init_data.reserve_indices(init_data.indices_count() + triangulation.size()); for (const Vec3d& v : triangulation) { init_data.add_vertex((Vec3f)(v.cast() + 0.015f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting ++vertices_counter; @@ -400,9 +400,9 @@ void GLVolume::NonManifoldEdges::update() if (!edges.empty()) { GUI::GLModel::Geometry init_data; #if ENABLE_GLBEGIN_GLEND_REMOVAL - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Lines, GUI::GLModel::Geometry::EVertexLayout::P3, GUI::GLModel::Geometry::EIndexType::UINT }; - init_data.vertices.reserve(2 * edges.size() * GUI::GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * edges.size() * GUI::GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Lines, GUI::GLModel::Geometry::EVertexLayout::P3, GUI::GLModel::Geometry::index_type(2 * edges.size()) }; + init_data.reserve_vertices(2 * edges.size()); + init_data.reserve_indices(2 * edges.size()); // vertices + indices unsigned int vertices_count = 0; @@ -410,7 +410,10 @@ void GLVolume::NonManifoldEdges::update() init_data.add_vertex((Vec3f)mesh.its.vertices[edge.first].cast()); init_data.add_vertex((Vec3f)mesh.its.vertices[edge.second].cast()); vertices_count += 2; - init_data.add_uint_line(vertices_count - 2, vertices_count - 1); + if (init_data.format.index_type == GUI::GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); + else + init_data.add_uint_line(vertices_count - 2, vertices_count - 1); } m_model.init_from(std::move(init_data)); #else @@ -681,13 +684,12 @@ std::vector GLVolumeCollection::load_object( const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, - const std::string &color_by, bool opengl_initialized) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized)); return volumes_idx; } @@ -696,16 +698,13 @@ int GLVolumeCollection::load_object_volume( int obj_idx, int volume_idx, int instance_idx, - const std::string &color_by, bool opengl_initialized) { const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; const TriangleMesh &mesh = model_volume->mesh(); - ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4]; - color.a(model_volume->is_model_part() ? 1.0f : 0.5f); - this->volumes.emplace_back(new GLVolume(color)); + this->volumes.emplace_back(new GLVolume()); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); #if ENABLE_SMOOTH_NORMALS diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 5aaa759f2f..c2e4e587ce 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -593,7 +593,6 @@ public: const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, - const std::string &color_by, bool opengl_initialized); int load_object_volume( @@ -601,7 +600,6 @@ public: int obj_idx, int volume_idx, int instance_idx, - const std::string &color_by, bool opengl_initialized); // Load SLA auxiliary GLVolumes (for support trees or pad). diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 5d3d47c202..37e527d649 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -165,17 +165,6 @@ void BackgroundSlicingProcess::process_fff() } } -static void write_thumbnail(Zipper& zipper, const ThumbnailData& data) -{ - size_t png_size = 0; - void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); - if (png_data != nullptr) - { - zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size); - mz_free(png_data); - } -} - void BackgroundSlicingProcess::process_sla() { assert(m_print == m_sla_print); @@ -189,12 +178,7 @@ void BackgroundSlicingProcess::process_sla() ThumbnailsList thumbnails = this->render_thumbnails( ThumbnailsParams{current_print()->full_print_config().option("thumbnails")->values, true, true, true, true}); - Zipper zipper(export_path); - m_sla_print->export_print(zipper); - for (const ThumbnailData& data : thumbnails) - if (data.is_valid()) - write_thumbnail(zipper, data); - zipper.finalize(); + m_sla_print->export_print(export_path, thumbnails); m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str()); } else if (! m_upload_job.empty()) { @@ -739,13 +723,7 @@ void BackgroundSlicingProcess::prepare_upload() ThumbnailsList thumbnails = this->render_thumbnails( ThumbnailsParams{current_print()->full_print_config().option("thumbnails")->values, true, true, true, true}); - // true, false, true, true); // renders also supports and pad - Zipper zipper{source_path.string()}; - m_sla_print->export_print(zipper, m_upload_job.upload_data.upload_path.string()); - for (const ThumbnailData& data : thumbnails) - if (data.is_valid()) - write_thumbnail(zipper, data); - zipper.finalize(); + m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.string()); } m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 367846f0c8..c86d16a1f0 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -103,7 +103,11 @@ void GCodeViewer::IBuffer::reset() count = 0; } +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC +bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move, bool account_for_volumetric_rate) const +#else bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) const +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC { auto matches_percent = [](float value1, float value2, float max_percent) { return std::abs(value2 - value1) / value1 <= max_percent; @@ -120,10 +124,22 @@ bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) co case EMoveType::Seam: case EMoveType::Extrude: { // use rounding to reduce the number of generated paths +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + if (account_for_volumetric_rate) + return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role && + move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed && + height == round_to_bin(move.height) && width == round_to_bin(move.width) && + matches_percent(volumetric_rate, move.volumetric_rate(), 0.001f); + else + return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role && + move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed && + height == round_to_bin(move.height) && width == round_to_bin(move.width); +#else return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role && move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed && height == round_to_bin(move.height) && width == round_to_bin(move.width) && matches_percent(volumetric_rate, move.volumetric_rate(), 0.05f); +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC } case EMoveType::Travel: { return type == move.type && feedrate == move.feedrate && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id; @@ -160,6 +176,66 @@ void GCodeViewer::TBuffer::add_path(const GCodeProcessorResult::MoveVertex& move move.volumetric_rate(), move.extruder_id, move.cp_color_id, { { endpoint, endpoint } } }); } +#if ENABLE_SHOW_TOOLPATHS_COG +void GCodeViewer::COG::render() +{ + if (!m_visible) + return; + + init(); + + GLShaderProgram* shader = wxGetApp().get_shader("toolpaths_cog"); + if (shader == nullptr) + return; + + shader->start_using(); + + glsafe(::glDisable(GL_DEPTH_TEST)); + + glsafe(::glPushMatrix()); + const Vec3d position = cog(); + glsafe(::glTranslated(position.x(), position.y(), position.z())); + if (m_fixed_size) { + const double inv_zoom = wxGetApp().plater()->get_camera().get_inv_zoom(); + glsafe(::glScaled(inv_zoom, inv_zoom, inv_zoom)); + } + m_model.render(); + + glsafe(::glPopMatrix()); + + shader->stop_using(); + + ////Show ImGui window + //static float last_window_width = 0.0f; + //static size_t last_text_length = 0; + + //ImGuiWrapper& imgui = *wxGetApp().imgui(); + //const Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); + //imgui.set_next_window_pos(0.5f * static_cast(cnv_size.get_width()), 0.0f, ImGuiCond_Always, 0.5f, 0.0f); + //ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + //ImGui::SetNextWindowBgAlpha(0.25f); + //imgui.begin(std::string("COG"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + //imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Center of mass") + ":"); + //ImGui::SameLine(); + //char buf[1024]; + //const Vec3d position = cog(); + //sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); + //imgui.text(std::string(buf)); + + //// force extra frame to automatically update window size + //const float width = ImGui::GetWindowWidth(); + //const size_t length = strlen(buf); + //if (width != last_window_width || length != last_text_length) { + // last_window_width = width; + // last_text_length = length; + // imgui.set_requires_extra_frame(); + //} + + //imgui.end(); + //ImGui::PopStyleVar(); +} +#endif // ENABLE_SHOW_TOOLPATHS_COG + #if ENABLE_PREVIEW_LAYER_TIME float GCodeViewer::Extrusions::Range::step_size(EType type) const { @@ -638,10 +714,19 @@ void GCodeViewer::init() void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized) { // avoid processing if called with the same gcode_result +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + if (m_last_result_id == gcode_result.id && + (m_last_view_type == m_view_type || (m_last_view_type != EViewType::VolumetricRate && m_view_type != EViewType::VolumetricRate))) + return; +#else if (m_last_result_id == gcode_result.id) return; +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC m_last_result_id = gcode_result.id; +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + m_last_view_type = m_view_type; +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC // release gpu memory, if used reset(); @@ -955,6 +1040,9 @@ unsigned int GCodeViewer::get_options_visibility_flags() const flags = set_flag(flags, static_cast(Preview::OptionType::ColorChanges), is_toolpath_move_type_visible(EMoveType::Color_change)); flags = set_flag(flags, static_cast(Preview::OptionType::PausePrints), is_toolpath_move_type_visible(EMoveType::Pause_Print)); flags = set_flag(flags, static_cast(Preview::OptionType::CustomGCodes), is_toolpath_move_type_visible(EMoveType::Custom_GCode)); +#if ENABLE_SHOW_TOOLPATHS_COG + flags = set_flag(flags, static_cast(Preview::OptionType::CenterOfGravity), m_cog.is_visible()); +#endif // ENABLE_SHOW_TOOLPATHS_COG flags = set_flag(flags, static_cast(Preview::OptionType::Shells), m_shells.visible); flags = set_flag(flags, static_cast(Preview::OptionType::ToolMarker), m_sequential_view.marker.is_visible()); #if !ENABLE_PREVIEW_LAYOUT @@ -978,6 +1066,9 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags) set_toolpath_move_type_visible(EMoveType::Color_change, is_flag_set(static_cast(Preview::OptionType::ColorChanges))); set_toolpath_move_type_visible(EMoveType::Pause_Print, is_flag_set(static_cast(Preview::OptionType::PausePrints))); set_toolpath_move_type_visible(EMoveType::Custom_GCode, is_flag_set(static_cast(Preview::OptionType::CustomGCodes))); +#if ENABLE_SHOW_TOOLPATHS_COG + m_cog.set_visible(is_flag_set(static_cast(Preview::OptionType::CenterOfGravity))); +#endif // ENABLE_SHOW_TOOLPATHS_COG m_shells.visible = is_flag_set(static_cast(Preview::OptionType::Shells)); m_sequential_view.marker.set_visible(is_flag_set(static_cast(Preview::OptionType::ToolMarker))); #if !ENABLE_PREVIEW_LAYOUT @@ -1200,9 +1291,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) // add current vertex add_vertex(curr); }; +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + auto add_indices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, + unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id, bool account_for_volumetric_rate) { + if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr, account_for_volumetric_rate)) { +#else auto add_indices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) { if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) { +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC // add starting index indices.push_back(static_cast(indices.size())); buffer.add_path(curr, ibuffer_id, indices.size() - 1, move_id - 1); @@ -1221,7 +1318,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) }; // format data into the buffers to be rendered as solid - auto add_vertices_as_solid = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id) { +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + auto add_vertices_as_solid = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, + unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id, bool account_for_volumetric_rate) { +#else + auto add_vertices_as_solid = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, + unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id) { +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC auto store_vertex = [](VertexBuffer& vertices, const Vec3f& position, const Vec3f& normal) { // append position vertices.push_back(position.x()); @@ -1233,7 +1336,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) vertices.push_back(normal.z()); }; +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr, account_for_volumetric_rate)) { +#else if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) { +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC buffer.add_path(curr, vbuffer_id, vertices.size(), move_id - 1); buffer.paths.back().sub_paths.back().first.position = prev.position; } @@ -1278,8 +1385,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) last_path.sub_paths.back().last = { vbuffer_id, vertices.size(), move_id, curr.position }; }; - auto add_indices_as_solid = [&](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, const GCodeProcessorResult::MoveVertex* next, - TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) { +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + auto add_indices_as_solid = [&](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, + const GCodeProcessorResult::MoveVertex* next, TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id, + IndexBuffer& indices, size_t move_id, bool account_for_volumetric_rate) { +#else + auto add_indices_as_solid = [&](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, + const GCodeProcessorResult::MoveVertex* next, TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id, + IndexBuffer& indices, size_t move_id) { +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC static Vec3f prev_dir; static Vec3f prev_up; static float sq_prev_length; @@ -1324,7 +1438,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) store_triangle(indices, v_offsets[4], v_offsets[5], v_offsets[6]); }; +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr, account_for_volumetric_rate)) { +#else if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) { +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC buffer.add_path(curr, ibuffer_id, indices.size(), move_id - 1); buffer.paths.back().sub_paths.back().first.position = prev.position; } @@ -1408,7 +1526,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) vbuffer_size += 6; } +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + if (next != nullptr && (curr.type != next->type || !last_path.matches(*next, account_for_volumetric_rate))) +#else if (next != nullptr && (curr.type != next->type || !last_path.matches(*next))) +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC // ending cap triangles append_ending_cap_triangles(indices, is_first_segment ? first_seg_v_offsets : non_first_seg_v_offsets); @@ -1537,6 +1659,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) if (wxGetApp().is_editor()) m_contained_in_bed = wxGetApp().plater()->build_volume().all_paths_inside(gcode_result, m_paths_bounding_box); +#if ENABLE_SHOW_TOOLPATHS_COG + m_cog.reset(); +#endif // ENABLE_SHOW_TOOLPATHS_COG + m_sequential_view.gcode_ids.clear(); for (size_t i = 0; i < gcode_result.moves.size(); ++i) { const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i]; @@ -1544,6 +1670,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) m_sequential_view.gcode_ids.push_back(move.gcode_id); } +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + bool account_for_volumetric_rate = m_view_type == EViewType::VolumetricRate; +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + std::vector vertices(m_buffers.size()); std::vector indices(m_buffers.size()); std::vector instances(m_buffers.size()); @@ -1551,18 +1681,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) std::vector instances_offsets(m_buffers.size()); std::vector options_zs; - size_t seams_count = 0; std::vector biased_seams_ids; // toolpaths data -> extract vertices from result for (size_t i = 0; i < m_moves_count; ++i) { const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i]; - if (curr.type == EMoveType::Seam) { - ++seams_count; + if (curr.type == EMoveType::Seam) biased_seams_ids.push_back(i - biased_seams_ids.size() - 1); - } - size_t move_id = i - seams_count; + const size_t move_id = i - biased_seams_ids.size(); // skip first vertex if (i == 0) @@ -1570,6 +1697,20 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) const GCodeProcessorResult::MoveVertex& prev = gcode_result.moves[i - 1]; +#if ENABLE_SHOW_TOOLPATHS_COG + if (curr.type == EMoveType::Extrude && + curr.extrusion_role != erSkirt && + curr.extrusion_role != erSupportMaterial && + curr.extrusion_role != erSupportMaterialInterface && + curr.extrusion_role != erWipeTower && + curr.extrusion_role != erCustom && + curr.extrusion_role != erMixed) { + const Vec3d curr_pos = curr.position.cast(); + const Vec3d prev_pos = prev.position.cast(); + m_cog.add_segment(curr_pos, prev_pos, curr.mm3_per_mm * (curr_pos - prev_pos).norm()); + } +#endif // ENABLE_SHOW_TOOLPATHS_COG + // update progress dialog ++progress_count; if (progress_dialog != nullptr && progress_count % progress_threshold == 0) { @@ -1597,7 +1738,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) v_multibuffer.push_back(VertexBuffer()); if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) { Path& last_path = t_buffer.paths.back(); +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + if (prev.type == curr.type && last_path.matches(curr, account_for_volumetric_rate)) +#else if (prev.type == curr.type && last_path.matches(curr)) +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC last_path.add_sub_path(prev, static_cast(v_multibuffer.size()) - 1, 0, move_id - 1); } } @@ -1608,7 +1753,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) { case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; } case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; } +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast(v_multibuffer.size()) - 1, v_buffer, move_id, account_for_volumetric_rate); break; } +#else case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast(v_multibuffer.size()) - 1, v_buffer, move_id); break; } +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC case TBuffer::ERenderPrimitiveType::InstancedModel: { add_model_instance(curr, inst_buffer, inst_id_buffer, move_id); @@ -1893,14 +2042,14 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) using VboIndexList = std::vector; std::vector vbo_indices(m_buffers.size()); - seams_count = 0; + size_t seams_count = 0; for (size_t i = 0; i < m_moves_count; ++i) { const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i]; if (curr.type == EMoveType::Seam) ++seams_count; - size_t move_id = i - seams_count; + const size_t move_id = i - seams_count; // skip first vertex if (i == 0) @@ -1972,12 +2121,20 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result) break; } case TBuffer::ERenderPrimitiveType::Line: { +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + add_indices_as_line(prev, curr, t_buffer, static_cast(i_multibuffer.size()) - 1, i_buffer, move_id, account_for_volumetric_rate); +#else add_indices_as_line(prev, curr, t_buffer, static_cast(i_multibuffer.size()) - 1, i_buffer, move_id); +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC curr_vertex_buffer.second += t_buffer.max_vertices_per_segment(); break; } case TBuffer::ERenderPrimitiveType::Triangle: { +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast(i_multibuffer.size()) - 1, i_buffer, move_id, account_for_volumetric_rate); +#else add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast(i_multibuffer.size()) - 1, i_buffer, move_id); +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC break; } case TBuffer::ERenderPrimitiveType::BatchedModel: { @@ -2149,7 +2306,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized) } size_t current_volumes_count = m_shells.volumes.volumes.size(); - m_shells.volumes.load_object(model_obj, object_id, instance_ids, "object", initialized); + m_shells.volumes.load_object(model_obj, object_id, instance_ids, initialized); // adjust shells' z if raft is present const SlicingParameters& slicing_parameters = obj->slicing_parameters(); @@ -4074,15 +4231,6 @@ void GCodeViewer::render_legend(float& legend_height) }; #if ENABLE_LEGEND_TOOLBAR_ICONS -// auto circle_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) { -// const float margin = 3.0f; -// const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size)); -// window.DrawList->AddCircleFilled(center, 0.5f * (size - 2.0f * margin), ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); -// }; -// auto line_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) { -// const float margin = 3.0f; -// window.DrawList->AddLine({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin, pos.y + margin }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f); -// }; auto image_icon = [&imgui](ImGuiWindow& window, const ImVec2& pos, float size, const wchar_t& icon_id) { ImGuiIO& io = ImGui::GetIO(); const ImTextureID tex_id = io.Fonts->TexID; @@ -4091,17 +4239,17 @@ void GCodeViewer::render_legend(float& legend_height) const ImFontAtlas::CustomRect* const rect = imgui.GetTextureCustomRect(icon_id); const ImVec2 uv0 = { static_cast(rect->X) / tex_w, static_cast(rect->Y) / tex_h }; const ImVec2 uv1 = { static_cast(rect->X + rect->Width) / tex_w, static_cast(rect->Y + rect->Height) / tex_h }; - window.DrawList->AddImage(tex_id, pos, { pos.x + size, pos.y + size }, uv0, uv1, ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 1.0f })); + window.DrawList->AddImage(tex_id, pos, { pos.x + size, pos.y + size }, uv0, uv1, ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f })); }; #else - auto circle_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) { - const float margin = 3.0f; + auto circle_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const ColorRGBA& color) { + const float margin = 3.0f; const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size)); - window.DrawList->AddCircleFilled(center, 0.5f * (size - 2.0f * margin), ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); + window.DrawList->AddCircleFilled(center, 0.5f * (size - 2.0f * margin), ImGuiWrapper::to_ImU32(color), 16); }; - auto line_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) { + auto line_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const ColorRGBA& color) { const float margin = 3.0f; - window.DrawList->AddLine({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin, pos.y + margin }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f); + window.DrawList->AddLine({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin, pos.y + margin }, ImGuiWrapper::to_ImU32(color), 3.0f); }; #endif // ENABLE_LEGEND_TOOLBAR_ICONS @@ -4190,12 +4338,41 @@ void GCodeViewer::render_legend(float& legend_height) #endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); +#if ENABLE_SHOW_TOOLPATHS_COG +#if ENABLE_LEGEND_TOOLBAR_ICONS + toggle_button(Preview::OptionType::CenterOfGravity, _u8L("Center of gravity"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { + image_icon(window, pos, size, ImGui::LegendCOG); + }); +#else + toggle_button(Preview::OptionType::CenterOfGravity, _u8L("Center of gravity"), [](ImGuiWindow& window, const ImVec2& pos, float size) { + const ImU32 black = ImGuiWrapper::to_ImU32({ 0.0f, 0.0f, 0.0f, 1.0f }); + const ImU32 white = ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f }); + const float margin = 3.0f; + const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size)); + const float radius = 0.5f * (size - 2.0f * margin); + window.DrawList->PathArcToFast(center, radius, 0, 3); + window.DrawList->PathLineTo(center); + window.DrawList->PathFillConvex(black); + window.DrawList->PathArcToFast(center, radius, 3, 6); + window.DrawList->PathLineTo(center); + window.DrawList->PathFillConvex(white); + window.DrawList->PathArcToFast(center, radius, 6, 9); + window.DrawList->PathLineTo(center); + window.DrawList->PathFillConvex(black); + window.DrawList->PathArcToFast(center, radius, 9, 12); + window.DrawList->PathLineTo(center); + window.DrawList->PathFillConvex(white); + window.DrawList->AddCircle(center, radius, black, 16); + }); +#endif // ENABLE_LEGEND_TOOLBAR_ICONS + ImGui::SameLine(); +#endif // ENABLE_SHOW_TOOLPATHS_COG #if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendShells); #else toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [](ImGuiWindow& window, const ImVec2& pos, float size) { - const ImU32 color = ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 1.0f }); + const ImU32 color = ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f }); const float margin = 3.0f; const float proj = 0.25f * size; window.DrawList->AddRect({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin - proj, pos.y + margin + proj }, color); @@ -4212,11 +4389,11 @@ void GCodeViewer::render_legend(float& legend_height) image_icon(window, pos, size, ImGui::LegendToolMarker); #else toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [](ImGuiWindow& window, const ImVec2& pos, float size) { - const ImU32 color = ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 0.8f }); + const ImU32 color = ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 0.8f }); const float margin = 3.0f; const ImVec2 p1(0.5f * (pos.x + pos.x + size), pos.y + size - margin); - const ImVec2 p2 = ImVec2(p1.x + 0.25f * size, p1.y - 0.25f * size); - const ImVec2 p3 = ImVec2(p1.x - 0.25f * size, p1.y - 0.25f * size); + const ImVec2 p2(p1.x + 0.25f * size, p1.y - 0.25f * size); + const ImVec2 p3(p1.x - 0.25f * size, p1.y - 0.25f * size); window.DrawList->AddTriangleFilled(p1, p2, p3, color); const float mid_x = 0.5f * (pos.x + pos.x + size); window.DrawList->AddRectFilled({ mid_x - 0.09375f * size, p1.y - 0.25f * size }, { mid_x + 0.09375f * size, pos.y + margin }, color); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index ecebb26414..b2b0626d51 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -212,7 +212,11 @@ class GCodeViewer unsigned char cp_color_id{ 0 }; std::vector sub_paths; +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + bool matches(const GCodeProcessorResult::MoveVertex& move, bool account_for_volumetric_rate) const; +#else bool matches(const GCodeProcessorResult::MoveVertex& move) const; +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC size_t vertices_count() const { return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1; } @@ -380,6 +384,52 @@ class GCodeViewer bool visible{ false }; }; +#if ENABLE_SHOW_TOOLPATHS_COG + // helper to render center of gravity + class COG + { + GLModel m_model; + bool m_visible{ false }; + // whether or not to render the model with fixed screen size + bool m_fixed_size{ true }; + double m_total_mass{ 0.0 }; + Vec3d m_position{ Vec3d::Zero() }; + + public: + void render(); + + void reset() { + m_position = Vec3d::Zero(); + m_total_mass = 0.0; + } + + bool is_visible() const { return m_visible; } + void set_visible(bool visible) { m_visible = visible; } + + void add_segment(const Vec3d& v1, const Vec3d& v2, double mass) { + assert(mass > 0.0); + m_position += mass * 0.5 * (v1 + v2); + m_total_mass += mass; + } + + Vec3d cog() const { return (m_total_mass > 0.0) ? (Vec3d)(m_position / m_total_mass) : Vec3d::Zero(); } + + private: + void init() { + if (m_model.is_initialized()) + return; + + const float radius = m_fixed_size ? 10.0f : 1.0f; + +#if ENABLE_GLBEGIN_GLEND_REMOVAL + m_model.init_from(smooth_sphere(32, radius)); +#else + m_model.init_from(its_make_sphere(radius, PI / 32.0)); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL + } + }; +#endif // ENABLE_SHOW_TOOLPATHS_COG + // helper to render extrusion paths struct Extrusions { @@ -716,6 +766,9 @@ public: private: bool m_gl_data_initialized{ false }; unsigned int m_last_result_id{ 0 }; +#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC + EViewType m_last_view_type{ EViewType::Count }; +#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC size_t m_moves_count{ 0 }; std::vector m_buffers{ static_cast(EMoveType::Extrude) }; // bounding box of toolpaths @@ -734,6 +787,9 @@ private: Extrusions m_extrusions; SequentialView m_sequential_view; Shells m_shells; +#if ENABLE_SHOW_TOOLPATHS_COG + COG m_cog; +#endif // ENABLE_SHOW_TOOLPATHS_COG EViewType m_view_type{ EViewType::FeatureType }; bool m_legend_enabled{ true }; #if ENABLE_PREVIEW_LAYOUT @@ -779,6 +835,9 @@ public: void reset(); void render(); +#if ENABLE_SHOW_TOOLPATHS_COG + void render_cog() { m_cog.render(); } +#endif // ENABLE_SHOW_TOOLPATHS_COG bool has_data() const { return !m_roles.empty(); } bool can_export_toolpaths() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 84cc2e5552..edd62ce0ab 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -368,8 +368,8 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices const float l = bar_rect.get_left(); @@ -428,8 +428,8 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; init_data.color = ColorRGBA::BLACK(); - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; @@ -447,16 +447,19 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) m_profile.profile.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::UINT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::index_type(m_layer_height_profile.size() / 2) }; init_data.color = ColorRGBA::BLUE(); - init_data.vertices.reserve(m_layer_height_profile.size() * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(m_layer_height_profile.size() * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(m_layer_height_profile.size() / 2); + init_data.reserve_indices(m_layer_height_profile.size() / 2); // vertices + indices for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y)); - init_data.add_uint_index(i / 2); + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_index((unsigned short)i / 2); + else + init_data.add_uint_index(i / 2); } m_profile.profile.init_from(std::move(init_data)); @@ -492,17 +495,17 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G { assert(this->is_allowed()); assert(this->last_object_id != -1); + + GLShaderProgram* current_shader = wxGetApp().get_current_shader(); + ScopeGuard guard([current_shader]() { if (current_shader != nullptr) current_shader->start_using(); }); + if (current_shader != nullptr) + current_shader->stop_using(); + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); if (shader == nullptr) return; - GLShaderProgram* current_shader = wxGetApp().get_current_shader(); - if (shader->get_id() != current_shader->get_id()) - // The layer editing shader is not yet active. Activate it. - shader->start_using(); - else - // The layer editing shader was already active. - current_shader = nullptr; + shader->start_using(); generate_layer_height_texture(); @@ -513,10 +516,10 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G shader->set_uniform("z_cursor_band_width", float(this->band_width)); // Initialize the layer height texture mapping. - GLsizei w = (GLsizei)m_layers_texture.width; - GLsizei h = (GLsizei)m_layers_texture.height; - GLsizei half_w = w / 2; - GLsizei half_h = h / 2; + const GLsizei w = (GLsizei)m_layers_texture.width; + const GLsizei h = (GLsizei)m_layers_texture.height; + const GLsizei half_w = w / 2; + const GLsizei half_h = h / 2; glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); @@ -525,17 +528,15 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4)); for (const GLVolume* glvolume : volumes.volumes) { // Render the object using the layer editing shader and texture. - if (! glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) + if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) continue; shader->set_uniform("volume_world_matrix", glvolume->world_matrix()); - shader->set_uniform("object_max_z", GLfloat(0)); + shader->set_uniform("object_max_z", 0.0f); glvolume->render(); } // Revert back to the previous shader. glBindTexture(GL_TEXTURE_2D, 0); - if (current_shader != nullptr) - current_shader->start_using(); } void GLCanvas3D::LayersEditing::adjust_layer_height_profile() @@ -898,6 +899,8 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons unsigned int vertices_counter = 0; for (const ExPolygon& poly : polygons_union) { const std::vector triangulation = triangulate_expolygon_3d(poly); + fill_data.reserve_vertices(fill_data.vertices_count() + triangulation.size()); + fill_data.reserve_indices(fill_data.indices_count() + triangulation.size()); for (const Vec3d& v : triangulation) { fill_data.add_vertex((Vec3f)(v.cast() + 0.0125f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting ++vertices_counter; @@ -1101,7 +1104,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_moving(false) , m_tab_down(false) , m_cursor_type(Standard) - , m_color_by("volume") , m_reload_delayed(false) #if ENABLE_RENDER_PICKING_PASS , m_show_picking_texture(false) @@ -1152,6 +1154,7 @@ bool GLCanvas3D::init() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); +#if !ENABLE_GLBEGIN_GLEND_REMOVAL // Set antialiasing / multisampling glsafe(::glDisable(GL_LINE_SMOOTH)); glsafe(::glDisable(GL_POLYGON_SMOOTH)); @@ -1181,6 +1184,7 @@ bool GLCanvas3D::init() // A handy trick -- have surface material mirror the color. glsafe(::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)); glsafe(::glEnable(GL_COLOR_MATERIAL)); +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); @@ -1351,11 +1355,6 @@ void GLCanvas3D::bed_shape_changed() m_dirty = true; } -void GLCanvas3D::set_color_by(const std::string& value) -{ - m_color_by = value; -} - void GLCanvas3D::refresh_camera_scene_box() { wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); @@ -1600,6 +1599,10 @@ void GLCanvas3D::render() #if ENABLE_RENDER_SELECTION_CENTER _render_selection_center(); #endif // ENABLE_RENDER_SELECTION_CENTER +#if ENABLE_SHOW_TOOLPATHS_COG + if (!m_main_toolbar.is_enabled()) + _render_gcode_cog(); +#endif // ENABLE_SHOW_TOOLPATHS_COG // we need to set the mouse's scene position here because the depth buffer // could be invalidated by the following gizmo render methods @@ -1796,7 +1799,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.emplace_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -2021,7 +2024,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // later in this function. it->volume_idx = m_volumes.volumes.size(); - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { @@ -5234,8 +5237,8 @@ void GLCanvas3D::_render_background() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec2f(-1.0f, -1.0f), Vec2f(0.0f, 0.0f)); @@ -5415,6 +5418,13 @@ void GLCanvas3D::_render_gcode() m_gcode_viewer.render(); } +#if ENABLE_SHOW_TOOLPATHS_COG +void GLCanvas3D::_render_gcode_cog() +{ + m_gcode_viewer.render_cog(); +} +#endif // ENABLE_SHOW_TOOLPATHS_COG + void GLCanvas3D::_render_selection() { float scale_factor = 1.0; @@ -5784,32 +5794,81 @@ void GLCanvas3D::_render_sla_slices() if (!obj->is_step_done(slaposSliceSupports)) continue; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + SlaCap::ObjectIdToModelsMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); + SlaCap::ObjectIdToModelsMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); +#else SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL { if (it_caps_bottom == m_sla_caps[0].triangles.end()) it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first; if (!m_sla_caps[0].matches(clip_min_z)) { m_sla_caps[0].z = clip_min_z; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + it_caps_bottom->second.object.reset(); + it_caps_bottom->second.supports.reset(); +#else it_caps_bottom->second.object.clear(); it_caps_bottom->second.supports.clear(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } if (it_caps_top == m_sla_caps[1].triangles.end()) it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first; if (!m_sla_caps[1].matches(clip_max_z)) { m_sla_caps[1].z = clip_max_z; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + it_caps_top->second.object.reset(); + it_caps_top->second.supports.reset(); +#else it_caps_top->second.object.clear(); it_caps_top->second.supports.clear(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLModel& bottom_obj_triangles = it_caps_bottom->second.object; + GLModel& bottom_sup_triangles = it_caps_bottom->second.supports; + GLModel& top_obj_triangles = it_caps_top->second.object; + GLModel& top_sup_triangles = it_caps_top->second.supports; +#else Pointf3s &bottom_obj_triangles = it_caps_bottom->second.object; Pointf3s &bottom_sup_triangles = it_caps_bottom->second.supports; Pointf3s &top_obj_triangles = it_caps_top->second.object; Pointf3s &top_sup_triangles = it_caps_top->second.supports; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL +#if ENABLE_GLBEGIN_GLEND_REMOVAL + auto init_model = [](GLModel& model, const Pointf3s& triangles, const ColorRGBA& color) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(triangles.size()) }; + init_data.reserve_vertices(triangles.size()); + init_data.reserve_indices(triangles.size() / 3); + init_data.color = color; + + unsigned int vertices_count = 0; + for (const Vec3d& v : triangles) { + init_data.add_vertex((Vec3f)v.cast()); + ++vertices_count; + if (vertices_count % 3 == 0) { + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)vertices_count - 3, (unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); + else + init_data.add_uint_triangle(vertices_count - 3, vertices_count - 2, vertices_count - 1); + } + } + + if (!init_data.is_empty()) + model.init_from(std::move(init_data)); + }; + + if ((!bottom_obj_triangles.is_initialized() || !bottom_sup_triangles.is_initialized() || + !top_obj_triangles.is_initialized() || !top_sup_triangles.is_initialized()) && !obj->get_slice_index().empty()) { +#else if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - !obj->get_slice_index().empty()) - { + !obj->get_slice_index().empty()) { +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value; bool left_handed = obj->is_left_handed(); @@ -5824,39 +5883,81 @@ void GLCanvas3D::_render_sla_slices() const SliceRecord& slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON)); // Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts. - double plane_shift_z = 0.002; + const double plane_shift_z = 0.002; if (slice_low.is_valid()) { const ExPolygons& obj_bottom = slice_low.get_slice(soModel); const ExPolygons& sup_bottom = slice_low.get_slice(soSupport); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + // calculate model bottom cap + if (!bottom_obj_triangles.is_initialized() && !obj_bottom.empty()) + init_model(bottom_obj_triangles, triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.37f, 0.0f, 1.0f }); + // calculate support bottom cap + if (!bottom_sup_triangles.is_initialized() && !sup_bottom.empty()) + init_model(bottom_sup_triangles, triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.0f, 0.37f, 1.0f }); +#else // calculate model bottom cap if (bottom_obj_triangles.empty() && !obj_bottom.empty()) bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed); // calculate support bottom cap if (bottom_sup_triangles.empty() && !sup_bottom.empty()) - bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed); + bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } if (slice_high.is_valid()) { const ExPolygons& obj_top = slice_high.get_slice(soModel); const ExPolygons& sup_top = slice_high.get_slice(soSupport); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + // calculate model top cap + if (!top_obj_triangles.is_initialized() && !obj_top.empty()) + init_model(top_obj_triangles, triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.37f, 0.0f, 1.0f }); + // calculate support top cap + if (!top_sup_triangles.is_initialized() && !sup_top.empty()) + init_model(top_sup_triangles, triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.0f, 0.37f, 1.0f }); +#else // calculate model top cap if (top_obj_triangles.empty() && !obj_top.empty()) top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed); // calculate support top cap if (top_sup_triangles.empty() && !sup_top.empty()) top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + for (const SLAPrintObject::Instance& inst : obj->instances()) { + glsafe(::glPushMatrix()); + glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); + glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); + if (obj->is_left_handed()) + // The polygons are mirrored by X. + glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); + + bottom_obj_triangles.render(); + top_obj_triangles.render(); + bottom_sup_triangles.render(); + top_sup_triangles.render(); + + glsafe(::glPopMatrix()); + } + + shader->stop_using(); + } +#else if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { for (const SLAPrintObject::Instance& inst : obj->instances()) { glsafe(::glPushMatrix()); - glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0)); - glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0)); + glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); + glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); if (obj->is_left_handed()) // The polygons are mirrored by X. - glsafe(::glScalef(-1.0, 1.0, 1.0)); + glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glColor3f(1.0f, 0.37f, 0.0f)); if (!bottom_obj_triangles.empty()) { @@ -5880,6 +5981,7 @@ void GLCanvas3D::_render_sla_slices() glsafe(::glPopMatrix()); } } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 93cd8f4242..a3c302baef 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -335,6 +335,16 @@ class GLCanvas3D struct SlaCap { +#if ENABLE_GLBEGIN_GLEND_REMOVAL + struct Triangles + { + GLModel object; + GLModel supports; + }; + typedef std::map ObjectIdToModelsMap; + double z; + ObjectIdToModelsMap triangles; +#else struct Triangles { Pointf3s object; @@ -343,6 +353,7 @@ class GLCanvas3D typedef std::map ObjectIdToTrianglesMap; double z; ObjectIdToTrianglesMap triangles; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL SlaCap() { reset(); } void reset() { z = DBL_MAX; triangles.clear(); } @@ -473,7 +484,7 @@ private: std::array m_clipping_planes; ClippingPlane m_camera_clipping_plane; bool m_use_clipping_planes; - SlaCap m_sla_caps[2]; + std::array m_sla_caps; std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false // see request_extra_frame() @@ -511,8 +522,6 @@ private: // I just don't want to do it now before a release (Lukas Matena 24.3.2019) bool m_render_sla_auxiliaries; - std::string m_color_by; - bool m_reload_delayed; #if ENABLE_RENDER_PICKING_PASS @@ -681,8 +690,6 @@ public: bool get_use_clipping_planes() const { return m_use_clipping_planes; } const std::array &get_clipping_planes() const { return m_clipping_planes; }; - void set_color_by(const std::string& value); - void refresh_camera_scene_box(); BoundingBoxf3 volumes_bounding_box() const; @@ -938,6 +945,9 @@ private: void _render_bed_for_picking(bool bottom); void _render_objects(GLVolumeCollection::ERenderType type); void _render_gcode(); +#if ENABLE_SHOW_TOOLPATHS_COG + void _render_gcode_cog(); +#endif // ENABLE_SHOW_TOOLPATHS_COG void _render_selection(); void _render_sequential_clearance(); #if ENABLE_RENDER_SELECTION_CENTER diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 8ac1e5534d..28a6a1ce7a 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -18,6 +18,16 @@ namespace Slic3r { namespace GUI { #if ENABLE_GLBEGIN_GLEND_REMOVAL +void GLModel::Geometry::reserve_vertices(size_t vertices_count) +{ + vertices.reserve(vertices_count * vertex_stride_floats(format)); +} + +void GLModel::Geometry::reserve_indices(size_t indices_count) +{ + indices.reserve(indices_count * index_stride_bytes(format)); +} + void GLModel::Geometry::add_vertex(const Vec2f& position) { assert(format.vertex_layout == EVertexLayout::P2); @@ -318,6 +328,11 @@ size_t GLModel::Geometry::index_stride_bytes(const Format& format) }; } +GLModel::Geometry::EIndexType GLModel::Geometry::index_type(size_t vertices_count) +{ + return (vertices_count < 65536) ? EIndexType::USHORT : EIndexType::UINT; +} + bool GLModel::Geometry::has_position(const Format& format) { switch (format.vertex_layout) @@ -470,8 +485,8 @@ void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bb Geometry& data = m_render_data.geometry; data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT }; - data.vertices.reserve(3 * its.indices.size() * Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(3 * its.indices.size() * Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(3 * its.indices.size()); + data.reserve_indices(3 * its.indices.size()); // vertices + indices unsigned int vertices_counter = 0; @@ -552,8 +567,8 @@ void GLModel::init_from(const Polygons& polygons, float z) segments_count += polygon.points.size(); } - data.vertices.reserve(2 * segments_count * Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(2 * segments_count * Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(2 * segments_count); + data.reserve_indices(2 * segments_count); // vertices + indices unsigned int vertices_counter = 0; @@ -720,8 +735,8 @@ void GLModel::render() const const Geometry& data = m_render_data.geometry; - GLenum mode = get_primitive_mode(data.format); - GLenum index_type = get_index_type(data.format); + const GLenum mode = get_primitive_mode(data.format); + const GLenum index_type = get_index_type(data.format); const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); const bool position = Geometry::has_position(data.format); @@ -1034,8 +1049,8 @@ GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, fl GLModel::Geometry data; #if ENABLE_GLBEGIN_GLEND_REMOVAL data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve((6 * resolution + 2) * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve((6 * resolution * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(6 * resolution + 2); + data.reserve_indices(6 * resolution * 3); #else GLModel::Geometry::Entity entity; entity.type = GLModel::EPrimitiveType::Triangles; @@ -1175,6 +1190,7 @@ GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, fl data.entities.emplace_back(entity); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL + return data; } @@ -1200,8 +1216,8 @@ GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float GLModel::Geometry data; #if ENABLE_GLBEGIN_GLEND_REMOVAL data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve((8 * (resolution + 1) + 30) * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(((8 * resolution + 16) * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(8 * (resolution + 1) + 30); + data.reserve_indices((8 * resolution + 16) * 3); #else GLModel::Geometry::Entity entity; entity.type = GLModel::EPrimitiveType::Triangles; @@ -1506,6 +1522,7 @@ GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float data.entities.emplace_back(entity); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL + return data; } @@ -1526,8 +1543,8 @@ GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_w GLModel::Geometry data; #if ENABLE_GLBEGIN_GLEND_REMOVAL data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve(42 * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve((24 * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(42); + data.reserve_indices(72); #else GLModel::Geometry::Entity entity; entity.type = GLModel::EPrimitiveType::Triangles; @@ -1699,6 +1716,7 @@ GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_w data.entities.emplace_back(entity); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL + return data; } @@ -1712,8 +1730,8 @@ GLModel::Geometry diamond(unsigned short resolution) GLModel::Geometry data; #if ENABLE_GLBEGIN_GLEND_REMOVAL data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve((resolution + 2) * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(((2 * (resolution + 1)) * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(resolution + 2); + data.reserve_indices((2 * (resolution + 1)) * 3); #else GLModel::Geometry::Entity entity; entity.type = GLModel::EPrimitiveType::Triangles; @@ -1724,7 +1742,7 @@ GLModel::Geometry diamond(unsigned short resolution) #if ENABLE_GLBEGIN_GLEND_REMOVAL // vertices for (unsigned short i = 0; i < resolution; ++i) { - float ii = float(i) * step; + const float ii = float(i) * step; const Vec3f p = { 0.5f * ::cos(ii), 0.5f * ::sin(ii), 0.0f }; append_vertex(data, p, p.normalized()); } @@ -1782,8 +1800,77 @@ GLModel::Geometry diamond(unsigned short resolution) data.entities.emplace_back(entity); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL + return data; } +#if ENABLE_GLBEGIN_GLEND_REMOVAL +#if ENABLE_SHOW_TOOLPATHS_COG +GLModel::Geometry smooth_sphere(unsigned short resolution, float radius) +{ + resolution = std::max(4, resolution); + resolution = std::min(256, resolution); // ensure no unsigned short overflow of indices + + const unsigned short sectorCount = /*2 **/ resolution; + const unsigned short stackCount = resolution; + + const float sectorStep = float(2.0 * M_PI / sectorCount); + const float stackStep = float(M_PI / stackCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.reserve_vertices((stackCount - 1) * sectorCount + 2); + data.reserve_indices((2 * (stackCount - 1) * sectorCount) * 3); + + // vertices + for (unsigned short i = 0; i <= stackCount; ++i) { + // from pi/2 to -pi/2 + const double stackAngle = 0.5 * M_PI - stackStep * i; + const double xy = double(radius) * ::cos(stackAngle); + const double z = double(radius) * ::sin(stackAngle); + if (i == 0 || i == stackCount) { + const Vec3f v(float(xy), 0.0f, float(z)); + data.add_vertex(v, (Vec3f)v.normalized()); + } + else { + for (unsigned short j = 0; j < sectorCount; ++j) { + // from 0 to 2pi + const double sectorAngle = sectorStep * j; + const Vec3f v(float(xy * std::cos(sectorAngle)), float(xy * std::sin(sectorAngle)), float(z)); + data.add_vertex(v, (Vec3f)v.normalized()); + } + } + } + + // triangles + for (unsigned short i = 0; i < stackCount; ++i) { + // Beginning of current stack. + unsigned short k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount); + const unsigned short k1_first = k1; + // Beginning of next stack. + unsigned short k2 = (i == 0) ? 1 : (k1 + sectorCount); + const unsigned short k2_first = k2; + for (unsigned short j = 0; j < sectorCount; ++j) { + // 2 triangles per sector excluding first and last stacks + unsigned short k1_next = k1; + unsigned short k2_next = k2; + if (i != 0) { + k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1); + data.add_ushort_triangle(k1, k2, k1_next); + } + if (i + 1 != stackCount) { + k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1); + data.add_ushort_triangle(k1_next, k2, k2_next); + } + k1 = k1_next; + k2 = k2_next; + } + } + + return data; +} +#endif // ENABLE_SHOW_TOOLPATHS_COG +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index c02f5186ca..72c50ee11c 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -80,11 +80,14 @@ namespace GUI { std::vector indices; ColorRGBA color{ ColorRGBA::BLACK() }; - 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 reserve_vertices(size_t vertices_count); + void reserve_indices(size_t indices_count); + + void add_vertex(const Vec2f& position); // EVertexLayout::P2 + void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 + void add_vertex(const Vec3f& position); // EVertexLayout::P3 + void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 + void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 void add_ushort_index(unsigned short id); void add_uint_index(unsigned int id); @@ -103,6 +106,8 @@ namespace GUI { unsigned int extract_uint_index(size_t id) const; unsigned short extract_ushort_index(size_t id) const; + bool is_empty() const { return vertices.empty() || indices.empty(); } + size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } size_t indices_count() const { return indices.size() / index_stride_bytes(format); } @@ -130,6 +135,8 @@ namespace GUI { static size_t index_stride_bytes(const Format& format); + static EIndexType index_type(size_t vertices_count); + static bool has_position(const Format& format); static bool has_normal(const Format& format); static bool has_tex_coord(const Format& format); @@ -256,6 +263,14 @@ namespace GUI { // the diamond is contained into a box with size [1, 1, 1] GLModel::Geometry diamond(unsigned short resolution); +#if ENABLE_GLBEGIN_GLEND_REMOVAL +#if ENABLE_SHOW_TOOLPATHS_COG + // create a sphere with the given resolution and smooth normals + // the origin of the sphere is in its center + GLModel::Geometry smooth_sphere(unsigned short resolution, float radius); +#endif // ENABLE_SHOW_TOOLPATHS_COG +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 5331d517d8..515da6de3a 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -126,8 +126,8 @@ namespace GUI { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(4 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(4); // vertices init_data.add_vertex(Vec2f(left, bottom)); diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index ae71e90afe..33ac9b6bcd 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -41,6 +41,10 @@ std::pair GLShadersManager::init() // used to render 3D scene background valid &= append_shader("background", { "background.vs", "background.fs" }); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL +#if ENABLE_SHOW_TOOLPATHS_COG + // used to render toolpaths center of gravity + valid &= append_shader("toolpaths_cog", { "toolpaths_cog.vs", "toolpaths_cog.fs" }); +#endif // ENABLE_SHOW_TOOLPATHS_COG // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); // used to render printbed diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 3b99397ad5..340bb78c3c 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -342,8 +342,8 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, #if ENABLE_GLBEGIN_GLEND_REMOVAL GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec2f(left, bottom), Vec2f(uvs.left_bottom.u, uvs.left_bottom.v)); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b55ba0d75e..b914d8db47 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -496,7 +496,7 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = { /* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } }, - /* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } }, + /* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv, ".pwmx"sv } }, }; // This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms. diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index d9c32e8293..97f8edde33 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -126,6 +126,9 @@ public: ColorChanges, PausePrints, CustomGCodes, +#if ENABLE_SHOW_TOOLPATHS_COG + CenterOfGravity, +#endif // ENABLE_SHOW_TOOLPATHS_COG Shells, ToolMarker, #if !ENABLE_PREVIEW_LAYOUT diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index ab29e90262..ff5d89f5eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -115,8 +115,8 @@ void GLGizmoCut::on_render() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec3f(min_x, min_y, plane_center.z())); @@ -160,8 +160,8 @@ void GLGizmoCut::on_render() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = ColorRGBA::YELLOW(); - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex((Vec3f)plane_center.cast()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index fd32c68fc1..ea15deb169 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -1,6 +1,9 @@ // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoFlatten.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#include "slic3r/GUI/GUI_App.hpp" +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" @@ -63,6 +66,14 @@ void GLGizmoFlatten::on_render() { const Selection& selection = m_parent.get_selection(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -76,21 +87,38 @@ void GLGizmoFlatten::on_render() if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + m_planes[i].vbo.render(); +#else glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data())); if (m_planes[i].vbo.has_VBOs()) m_planes[i].vbo.render(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } glsafe(::glPopMatrix()); } glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); + +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + shader->stop_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } void GLGizmoFlatten::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_BLEND)); @@ -102,13 +130,21 @@ void GLGizmoFlatten::on_render_for_picking() if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + m_planes[i].vbo.set_color(picking_color_component(i)); +#else glsafe(::glColor4fv(picking_color_component(i).data())); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL m_planes[i].vbo.render(); } glsafe(::glPopMatrix()); } glsafe(::glEnable(GL_CULL_FACE)); + +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + shader->stop_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) @@ -324,12 +360,28 @@ void GLGizmoFlatten::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(plane.vertices.size()) }; + init_data.reserve_vertices(plane.vertices.size()); + init_data.reserve_indices(plane.vertices.size()); + // vertices + indices + for (size_t i = 0; i < plane.vertices.size(); ++i) { + init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_index((unsigned short)i); + else + init_data.add_uint_index((unsigned int)i); + } + plane.vbo.init_from(std::move(init_data)); +#else plane.vbo.reserve(plane.vertices.size()); for (const auto& vert : plane.vertices) plane.vbo.push_geometry(vert, plane.normal); for (size_t i=1; i vertices; // should be in fact local in update_planes() +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLModel vbo; +#else GLIndexedVertexArray vbo; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL Vec3d normal; float area; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 4c204d0d4c..dd9cf0de2e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -589,6 +589,9 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) m_gizmo_scene.render(color_idx); } +#if ENABLE_GLBEGIN_GLEND_REMOVAL + render_paint_contour(); +#else if (m_paint_contour.has_VBO()) { ScopeGuard guard_mm_gouraud([shader]() { shader->start_using(); }); shader->stop_using(); @@ -602,6 +605,7 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) contour_shader->stop_using(); } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL m_update_render_data = false; } @@ -636,6 +640,9 @@ void TriangleSelectorMmGui::update_render_data() m_gizmo_scene.finalize_triangle_indices(); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + update_paint_contour(); +#else m_paint_contour.release_geometry(); std::vector contour_edges = this->get_seed_fill_contour(); m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); @@ -654,6 +661,7 @@ void TriangleSelectorMmGui::update_render_data() m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); m_paint_contour.finalize_geometry(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 4cc28b3637..f7af6ba4a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -184,8 +184,8 @@ void GLGizmoMove3D::on_render() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = AXES_COLOR[id]; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices #if ENABLE_WORLD_COORDINATE diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 4c76767bd7..82a816d1b9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -18,7 +18,11 @@ namespace Slic3r::GUI { - std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; +#else +std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -27,8 +31,13 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic GLGizmoPainterBase::~GLGizmoPainterBase() { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + if (s_sphere != nullptr) + s_sphere.reset(); +#else if (s_sphere != nullptr && s_sphere->has_VBOs()) s_sphere->release_geometry(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) @@ -185,8 +194,8 @@ void GLGizmoPainterBase::render_cursor_circle() static const float StepSize = 2.0f * float(PI) / float(StepsCount); init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = { 0.0f, 1.0f, 0.3f, 1.0f }; - init_data.vertices.reserve(StepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(StepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(StepsCount); + init_data.reserve_indices(StepsCount); // vertices + indices for (unsigned short i = 0; i < StepsCount; ++i) { @@ -220,18 +229,27 @@ void GLGizmoPainterBase::render_cursor_circle() void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const { if (s_sphere == nullptr) { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + s_sphere = std::make_shared(); + s_sphere->init_from(its_make_sphere(1.0, double(PI) / 12.0)); +#else s_sphere = std::make_shared(); s_sphere->load_its_flat_shading(its_make_sphere(1.0, double(PI) / 12.0)); s_sphere->finalize_geometry(true); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse(); const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed(); glsafe(::glPushMatrix()); glsafe(::glMultMatrixd(trafo.data())); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glTranslatef(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2))); + glsafe(::glTranslatef(m_rr.hit.x(), m_rr.hit.y(), m_rr.hit.z())); glsafe(::glMultMatrixd(complete_scaling_matrix_inverse.data())); glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius)); @@ -243,11 +261,22 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const render_color = this->get_cursor_sphere_left_button_color(); else if (m_button_down == Button::Right) render_color = this->get_cursor_sphere_right_button_color(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + shader->start_using(); + + assert(s_sphere != nullptr); + s_sphere->set_color(render_color); +#else glsafe(::glColor4fv(render_color.data())); assert(s_sphere != nullptr); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL s_sphere->render(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + shader->stop_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + if (is_left_handed) glFrontFace(GL_CCW); @@ -763,13 +792,28 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) shader->set_uniform("offset_depth_buffer", true); for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), std::make_pair(&m_iva_blockers, blockers_color)}) { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + iva.first->set_color(iva.second); + iva.first->render(); +#else if (iva.first->has_VBOs()) { shader->set_uniform("uniform_color", iva.second); iva.first->render(); } +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } - for (auto &iva : m_iva_seed_fills) +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + for (auto& iva : m_iva_seed_fills) { + size_t color_idx = &iva - &m_iva_seed_fills.front(); + const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : + color_idx == 2 ? blockers_color : + GLVolume::NEUTRAL_COLOR); + iva.set_color(color); + iva.render(); + } +#else + for (auto& iva : m_iva_seed_fills) if (iva.has_VBOs()) { size_t color_idx = &iva - &m_iva_seed_fills.front(); const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : @@ -778,7 +822,11 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) shader->set_uniform("uniform_color", color); iva.render(); } +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#if ENABLE_GLBEGIN_GLEND_REMOVAL + render_paint_contour(); +#else if (m_paint_contour.has_VBO()) { ScopeGuard guard_gouraud([shader]() { shader->start_using(); }); shader->stop_using(); @@ -792,13 +840,14 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) contour_shader->stop_using(); } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG if (imgui) render_debug(imgui); else assert(false); // If you want debug output, pass ptr to ImGuiWrapper. -#endif +#endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG } void TriangleSelectorGUI::update_render_data() @@ -807,20 +856,44 @@ void TriangleSelectorGUI::update_render_data() int blc_cnt = 0; std::vector seed_fill_cnt(m_iva_seed_fills.size(), 0); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + for (auto* iva : { &m_iva_enforcers, &m_iva_blockers }) { + iva->reset(); + } + + for (auto& iva : m_iva_seed_fills) { + iva.reset(); + } + + GLModel::Geometry iva_enforcers_data; + iva_enforcers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + GLModel::Geometry iva_blockers_data; + iva_blockers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + std::array iva_seed_fills_data; + for (auto& data : iva_seed_fills_data) + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; +#else for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) iva->release_geometry(); for (auto &iva : m_iva_seed_fills) iva.release_geometry(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL for (const Triangle &tr : m_triangles) { if (!tr.valid() || tr.is_split() || (tr.get_state() == EnforcerBlockerType::NONE && !tr.is_selected_by_seed_fill())) continue; int tr_state = int(tr.get_state()); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLModel::Geometry &iva = tr.is_selected_by_seed_fill() ? iva_seed_fills_data[tr_state] : + tr.get_state() == EnforcerBlockerType::ENFORCER ? iva_enforcers_data : + iva_blockers_data; +#else GLIndexedVertexArray &iva = tr.is_selected_by_seed_fill() ? m_iva_seed_fills[tr_state] : tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL int &cnt = tr.is_selected_by_seed_fill() ? seed_fill_cnt[tr_state] : tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; @@ -830,19 +903,40 @@ void TriangleSelectorGUI::update_render_data() //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort // or the current implementation may be more cache friendly. const Vec3f n = (v1 - v0).cross(v2 - v1).normalized(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + iva.add_vertex(v0, n); + iva.add_vertex(v1, n); + iva.add_vertex(v2, n); + iva.add_uint_triangle((unsigned int)cnt, (unsigned int)cnt + 1, (unsigned int)cnt + 2); +#else iva.push_geometry(v0, n); iva.push_geometry(v1, n); iva.push_geometry(v2, n); iva.push_triangle(cnt, cnt + 1, cnt + 2); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL cnt += 3; } +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + if (!iva_enforcers_data.is_empty()) + m_iva_enforcers.init_from(std::move(iva_enforcers_data)); + if (!iva_blockers_data.is_empty()) + m_iva_blockers.init_from(std::move(iva_blockers_data)); + for (size_t i = 0; i < m_iva_seed_fills.size(); ++i) { + if (!iva_seed_fills_data[i].is_empty()) + m_iva_seed_fills[i].init_from(std::move(iva_seed_fills_data[i])); + } +#else for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) iva->finalize_geometry(true); for (auto &iva : m_iva_seed_fills) iva.finalize_geometry(true); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#if ENABLE_GLBEGIN_GLEND_REMOVAL + update_paint_contour(); +#else m_paint_contour.release_geometry(); std::vector contour_edges = this->get_seed_fill_contour(); m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); @@ -861,8 +955,10 @@ void TriangleSelectorGUI::update_render_data() m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); m_paint_contour.finalize_geometry(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } +#if !ENABLE_GLBEGIN_GLEND_REMOVAL void GLPaintContour::render() const { assert(this->m_contour_VBO_id != 0); @@ -920,6 +1016,7 @@ void GLPaintContour::release_geometry() } this->clear(); } +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) @@ -956,45 +1053,111 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) INVALID }; +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + for (auto& va : m_varrays) + va.reset(); +#else for (auto& va : m_varrays) va.release_geometry(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL std::array cnts; ::glScalef(1.01f, 1.01f, 1.01f); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + std::array varrays_data; + for (auto& data : varrays_data) + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + for (int tr_id=0; tr_idadd_vertex(m_vertices[tr.verts_idxs[i]].v, Vec3f(0.0f, 0.0f, 1.0f)); + } + va->add_uint_triangle((unsigned int)*cnt, (unsigned int)*cnt + 1, (unsigned int)*cnt + 2); +#else + for (int i = 0; i < 3; ++i) va->push_geometry(double(m_vertices[tr.verts_idxs[i]].v[0]), double(m_vertices[tr.verts_idxs[i]].v[1]), double(m_vertices[tr.verts_idxs[i]].v[2]), 0., 0., 1.); va->push_triangle(*cnt, - *cnt+1, - *cnt+2); + *cnt + 1, + *cnt + 2); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL *cnt += 3; } +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + for (int i = 0; i < 3; ++i) { + if (!varrays_data[i].is_empty()) + m_varrays[i].init_from(std::move(varrays_data[i])); + } +#else + for (auto* iva : { &m_iva_enforcers, &m_iva_blockers }) + iva->finalize_geometry(true); + + for (auto& iva : m_iva_seed_fills) + iva.finalize_geometry(true); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + ::glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); for (vtype i : {ORIGINAL, SPLIT, INVALID}) { +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLModel& va = m_varrays[i]; + switch (i) { + case ORIGINAL: va.set_color({ 0.0f, 0.0f, 1.0f, 1.0f }); break; + case SPLIT: va.set_color({ 1.0f, 0.0f, 0.0f, 1.0f }); break; + case INVALID: va.set_color({ 1.0f, 1.0f, 0.0f, 1.0f }); break; + } + va.render(); +#else GLIndexedVertexArray& va = m_varrays[i]; va.finalize_geometry(true); if (va.has_VBOs()) { @@ -1005,11 +1168,66 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) } va.render(); } +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } ::glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } -#endif +#endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG +#if ENABLE_GLBEGIN_GLEND_REMOVAL +void TriangleSelectorGUI::update_paint_contour() +{ + m_paint_contour.reset(); + GLModel::Geometry init_data; + const std::vector contour_edges = this->get_seed_fill_contour(); + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * contour_edges.size()) }; + init_data.reserve_vertices(2 * contour_edges.size()); + init_data.reserve_indices(2 * contour_edges.size()); + // vertices + indices + unsigned int vertices_count = 0; + for (const Vec2i& edge : contour_edges) { + init_data.add_vertex(m_vertices[edge(0)].v); + init_data.add_vertex(m_vertices[edge(1)].v); + vertices_count += 2; + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); + else + init_data.add_uint_line(vertices_count - 2, vertices_count - 1); + } + + if (!init_data.is_empty()) + m_paint_contour.init_from(std::move(init_data)); +} + +void TriangleSelectorGUI::render_paint_contour() +{ + auto* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + auto* contour_shader = wxGetApp().get_shader("mm_contour"); + if (contour_shader != nullptr) { + contour_shader->start_using(); + + glsafe(::glDepthFunc(GL_LEQUAL)); + m_paint_contour.render(); + glsafe(::glDepthFunc(GL_LESS)); + + contour_shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); +} +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 079f3f08ed..37c7163e2f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -3,7 +3,11 @@ #include "GLGizmoBase.hpp" +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#include "slic3r/GUI/GLModel.hpp" +#else #include "slic3r/GUI/3DScene.hpp" +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL #include "libslic3r/ObjectID.hpp" #include "libslic3r/TriangleSelector.hpp" @@ -28,6 +32,7 @@ enum class PainterGizmoType { MMU_SEGMENTATION }; +#if !ENABLE_GLBEGIN_GLEND_REMOVAL class GLPaintContour { public: @@ -63,6 +68,7 @@ public: GLuint m_contour_VBO_id{0}; GLuint m_contour_EBO_id{0}; }; +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL class TriangleSelectorGUI : public TriangleSelector { public: @@ -75,13 +81,13 @@ public: virtual void render(ImGuiWrapper *imgui); void render() { this->render(nullptr); } - void request_update_render_data() { m_update_render_data = true; }; + void request_update_render_data() { m_update_render_data = true; } #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void render_debug(ImGuiWrapper* imgui); bool m_show_triangles{false}; bool m_show_invalid{false}; -#endif +#endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG protected: bool m_update_render_data = false; @@ -91,13 +97,29 @@ protected: private: void update_render_data(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLModel m_iva_enforcers; + GLModel m_iva_blockers; + std::array m_iva_seed_fills; +#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG + std::array m_varrays; +#endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG +#else GLIndexedVertexArray m_iva_enforcers; GLIndexedVertexArray m_iva_blockers; std::array m_iva_seed_fills; std::array m_varrays; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL protected: +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLModel m_paint_contour; + + void update_paint_contour(); + void render_paint_contour(); +#else GLPaintContour m_paint_contour; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL }; @@ -209,7 +231,11 @@ private: const Camera& camera, const std::vector& trafo_matrices) const; +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + static std::shared_ptr s_sphere; +#else static std::shared_ptr s_sphere; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL bool m_internal_stack_active = false; bool m_schedule_update = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index a8e2c470aa..8f42ee666f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -314,8 +314,8 @@ void GLGizmoRotate::render_circle() const GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(ScaleStepsCount); + init_data.reserve_indices(ScaleStepsCount); // vertices + indices for (unsigned short i = 0; i < ScaleStepsCount; ++i) { @@ -357,8 +357,8 @@ void GLGizmoRotate::render_scale() const GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); // vertices + indices for (unsigned short i = 0; i < ScaleStepsCount; ++i) { @@ -416,8 +416,8 @@ void GLGizmoRotate::render_snap_radii() const GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); // vertices + indices for (unsigned short i = 0; i < ScaleStepsCount; ++i) { @@ -467,8 +467,8 @@ void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_ GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); @@ -508,8 +508,8 @@ void GLGizmoRotate::render_angle() const GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve((1 + AngleResolution) * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve((1 + AngleResolution) * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(1 + AngleResolution); + init_data.reserve_indices(1 + AngleResolution); // vertices + indices for (unsigned short i = 0; i <= AngleResolution; ++i) { @@ -545,8 +545,8 @@ void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radiu GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 6de51c9802..b1c20a9f05 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -531,8 +531,8 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex((Vec3f)m_grabbers[id_1].center.cast()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 3406c58a29..fa0b27269a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -127,6 +127,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (! has_points && ! has_holes) return; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + ScopeGuard guard([shader]() { shader->stop_using(); }); +#else GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) shader->start_using(); @@ -134,6 +142,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (shader != nullptr) shader->stop_using(); }); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); @@ -177,11 +186,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) #if ENABLE_GLBEGIN_GLEND_REMOVAL m_cone.set_color(render_color); m_sphere.set_color(render_color); + if (!picking) #else m_cone.set_color(-1, render_color); m_sphere.set_color(-1, render_color); -#endif // ENABLE_GLBEGIN_GLEND_REMOVAL if (shader && !picking) +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL shader->set_uniform("emission_factor", 0.5f); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. @@ -236,9 +246,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) m_cylinder.set_color(render_color); #else m_cylinder.set_color(-1, render_color); + if (shader != nu) #endif // ENABLE_GLBEGIN_GLEND_REMOVAL - if (shader) - shader->set_uniform("emission_factor", 0.5f); + shader->set_uniform("emission_factor", 0.5f); for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { if (is_mesh_point_clipped(drain_hole.pos.cast())) continue; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index cc53f267c0..1e49ebc8c3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -213,15 +213,21 @@ void InstancesHider::render_cut() const clipper->set_limiting_plane(ClippingPlane::ClipsNothing()); glsafe(::glPushMatrix()); +#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL if (mv->is_model_part()) glsafe(::glColor3f(0.8f, 0.3f, 0.0f)); else { const ColorRGBA color = color_from_model_volume(*mv); glsafe(::glColor4fv(color.data())); } +#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL glsafe(::glPushAttrib(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST)); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + clipper->render_cut(mv->is_model_part() ? ColorRGBA(0.8f, 0.3f, 0.0f, 1.0f) : color_from_model_volume(*mv)); +#else clipper->render_cut(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL glsafe(::glPopAttrib()); glsafe(::glPopMatrix()); @@ -417,8 +423,12 @@ void ObjectClipper::render_cut() const clipper->set_transformation(trafo); clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); glsafe(::glPushMatrix()); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + clipper->render_cut({ 1.0f, 0.37f, 0.0f, 1.0f }); +#else glsafe(::glColor3f(1.0f, 0.37f, 0.0f)); clipper->render_cut(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL glsafe(::glPopMatrix()); ++clipper_id; @@ -530,8 +540,12 @@ void SupportsClipper::render_cut() const m_clipper->set_transformation(supports_trafo); glsafe(::glPushMatrix()); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); +#else glsafe(::glColor3f(1.0f, 0.f, 0.37f)); m_clipper->render_cut(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL glsafe(::glPopMatrix()); } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 4616eee85d..e70c1111b9 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -64,6 +64,9 @@ static const std::map font_icons = { {ImGui::LegendColorChanges , "legend_colorchanges" }, {ImGui::LegendPausePrints , "legend_pauseprints" }, {ImGui::LegendCustomGCodes , "legend_customgcodes" }, +#if ENABLE_SHOW_TOOLPATHS_COG + {ImGui::LegendCOG , "legend_cog" }, +#endif // ENABLE_SHOW_TOOLPATHS_COG {ImGui::LegendShells , "legend_shells" }, {ImGui::LegendToolMarker , "legend_toolmarker" }, #endif // ENABLE_LEGEND_TOOLBAR_ICONS diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 440b0ec0db..3787abb2f7 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -6,6 +6,9 @@ #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Model.hpp" +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#include "slic3r/GUI/GUI_App.hpp" +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL #include "slic3r/GUI/Camera.hpp" #include @@ -66,13 +69,34 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo) +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +void MeshClipper::render_cut(const ColorRGBA& color) +#else void MeshClipper::render_cut() +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL { if (! m_triangles_valid) recalculate_triangles(); +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + m_model.set_color(color); + m_model.render(); + shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); +#else if (m_vertex_array.has_VBOs()) m_vertex_array.render(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL } @@ -161,6 +185,29 @@ void MeshClipper::recalculate_triangles() tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + m_model.reset(); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(m_triangles2d.size()) }; + init_data.reserve_vertices(m_triangles2d.size()); + init_data.reserve_indices(m_triangles2d.size()); + + // vertices + indices + for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - m_triangles2d.cbegin(); + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); + else + init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + } + + if (!init_data.is_empty()) + m_model.init_from(std::move(init_data)); +#else m_vertex_array.release_geometry(); for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) { m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); @@ -170,6 +217,7 @@ void MeshClipper::recalculate_triangles() m_vertex_array.push_triangle(idx, idx+1, idx+2); } m_vertex_array.finalize_geometry(true); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL m_triangles_valid = true; } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index bb8a1aa618..cc961ee8f1 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -3,10 +3,15 @@ #include "libslic3r/Point.hpp" #include "libslic3r/Geometry.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/SLA/IndexedMesh.hpp" #include "admesh/stl.h" +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#include "slic3r/GUI/GLModel.hpp" +#else #include "slic3r/GUI/3DScene.hpp" +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL #include @@ -69,7 +74,8 @@ public: // MeshClipper class cuts a mesh and is able to return a triangulated cut. -class MeshClipper { +class MeshClipper +{ public: // Inform MeshClipper about which plane we want to use to cut the mesh // This is supposed to be in world coordinates. @@ -92,7 +98,11 @@ public: // Render the triangulated cut. Transformation matrices should // be set in world coords. +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + void render_cut(const ColorRGBA& color); +#else void render_cut(); +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL private: void recalculate_triangles(); @@ -103,7 +113,11 @@ private: ClippingPlane m_plane; ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing(); std::vector m_triangles2d; +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + GLModel m_model; +#else GLIndexedVertexArray m_vertex_array; +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL bool m_triangles_valid = false; }; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 4cedc1194e..381502d5b3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1429,10 +1429,10 @@ void Selection::render(float scale_factor) return; m_scale_factor = scale_factor; + // render cumulative bounding box of selected volumes #if ENABLE_GLBEGIN_GLEND_REMOVAL render_bounding_box(get_bounding_box(), ColorRGB::WHITE()); #else - // render cumulative bounding box of selected volumes render_selected_volumes(); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL render_synchronized_volumes(); @@ -1444,6 +1444,14 @@ void Selection::render_center(bool gizmo_is_dragging) if (!m_valid || is_empty()) return; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL + const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center(); glsafe(::glDisable(GL_DEPTH_TEST)); @@ -1452,19 +1460,17 @@ void Selection::render_center(bool gizmo_is_dragging) glsafe(::glTranslated(center.x(), center.y(), center.z())); #if ENABLE_GLBEGIN_GLEND_REMOVAL - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader == nullptr) - return; - - shader->start_using(); -#endif // ENABLE_GLBEGIN_GLEND_REMOVAL + m_vbo_sphere.set_color(ColorRGBA::WHITE()); +#else m_vbo_sphere.set_color(-1, ColorRGBA::WHITE()); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL m_vbo_sphere.render(); + + glsafe(::glPopMatrix()); + #if ENABLE_GLBEGIN_GLEND_REMOVAL shader->stop_using(); #endif // ENABLE_GLBEGIN_GLEND_REMOVAL - - glsafe(::glPopMatrix()); } #endif // ENABLE_RENDER_SELECTION_CENTER @@ -2086,8 +2092,8 @@ void Selection::render_bounding_box(const BoundingBoxf3 & box, float* color) con GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(48 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(48 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(48); + init_data.reserve_indices(48); // vertices init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z())); @@ -2395,8 +2401,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec3f(p1.x(), p1.y(), z1)); @@ -2417,8 +2423,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec3f(p1.x(), p1.y(), z2)); diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp index 049de5400a..533c544a8a 100644 --- a/src/slic3r/Utils/UndoRedo.cpp +++ b/src/slic3r/Utils/UndoRedo.cpp @@ -21,6 +21,10 @@ #include #include +#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL +#include "slic3r/GUI/3DScene.hpp" +#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL + #include #ifndef NDEBUG diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index cfadaf8785..06fc98322f 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -210,15 +210,24 @@ else () endif () 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 (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_CROSSCOMPILING 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}") + # On Centos 7 calling "gcc -print-file-name=libasan.so" returns path to "ld script" instead of path to shared library. + set(_asan_compiled_bin ${CMAKE_CURRENT_BINARY_DIR}/detect_libasan) + set(_asan_source_file ${_asan_compiled_bin}.c) + # Compile and link simple C application with enabled address sanitizer. + file(WRITE ${_asan_source_file} "int main(){}") + include(GetPrerequisites) + execute_process(COMMAND ${CMAKE_C_COMPILER} ${_asan_source_file} -fsanitize=address -lasan -o ${_asan_compiled_bin}) + # Extract from the compiled application absolute path of libasan. + get_prerequisites(${_asan_compiled_bin} _asan_shared_libraries_list 0 0 "" "") + list(FILTER _asan_shared_libraries_list INCLUDE REGEX libasan) + set(PERL_ENV_VARS ${PERL_ENV_VARS} "LD_PRELOAD=${_asan_shared_libraries_list}") # Suppressed memory leak reports that come from Perl. set(PERL_LEAK_SUPPRESSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/leak_suppression.txt)