diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 3d6d23f32c..e42e1a4888 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -212,6 +212,12 @@ void AppConfig::set_defaults() set("preview_reduced_detail_mode", "no_infill"); } + { + const std::string mode = get("preview_rest_detail_mode"); + if (mode != "full" && mode != "no_infill" && mode != "shell") + set("preview_rest_detail_mode", "full"); + } + if (get("preview_reduced_detail_layer_stride").empty()) set("preview_reduced_detail_layer_stride", "4"); else { diff --git a/src/libvgcode/include/Viewer.hpp b/src/libvgcode/include/Viewer.hpp index 5ddee75533..c5c5c15222 100644 --- a/src/libvgcode/include/Viewer.hpp +++ b/src/libvgcode/include/Viewer.hpp @@ -112,6 +112,12 @@ public: void set_reduced_detail_mode(EReducedDetailMode mode); uint32_t get_reduced_detail_layer_stride() const; void set_reduced_detail_layer_stride(uint32_t value); + // + // ORCA: what is left out even at rest, with every layer drawn. Off draws everything. + // EReducedDetailMode::LayersOnly means the same as Off here. + // + EReducedDetailMode get_rest_detail_mode() const; + void set_rest_detail_mode(EReducedDetailMode mode); float get_dim_previous_layers_brightness() const; void set_dim_previous_layers_brightness(float value); // diff --git a/src/libvgcode/src/Settings.hpp b/src/libvgcode/src/Settings.hpp index 0f3011f4d2..5346e3700c 100644 --- a/src/libvgcode/src/Settings.hpp +++ b/src/libvgcode/src/Settings.hpp @@ -33,6 +33,9 @@ struct Settings bool reduced_detail{ false }; EReducedDetailMode reduced_detail_mode{ EReducedDetailMode::Off }; uint32_t reduced_detail_layer_stride{ 4 }; + // ORCA: what is left out even at rest, with every layer drawn. Bound whenever the reduced set + // above is not. Off draws everything. + EReducedDetailMode rest_detail_mode{ EReducedDetailMode::Off }; // // Required update flags // diff --git a/src/libvgcode/src/Viewer.cpp b/src/libvgcode/src/Viewer.cpp index 883abf8df7..44e6d94967 100644 --- a/src/libvgcode/src/Viewer.cpp +++ b/src/libvgcode/src/Viewer.cpp @@ -107,6 +107,16 @@ void Viewer::set_reduced_detail_layer_stride(uint32_t value) m_impl->set_reduced_detail_layer_stride(value); } +EReducedDetailMode Viewer::get_rest_detail_mode() const +{ + return m_impl->get_rest_detail_mode(); +} + +void Viewer::set_rest_detail_mode(EReducedDetailMode mode) +{ + m_impl->set_rest_detail_mode(mode); +} + void Viewer::set_dim_previous_layers(bool value) { m_impl->set_dim_previous_layers(value); diff --git a/src/libvgcode/src/ViewerImpl.cpp b/src/libvgcode/src/ViewerImpl.cpp index 91e9ad1958..1d52101faa 100644 --- a/src/libvgcode/src/ViewerImpl.cpp +++ b/src/libvgcode/src/ViewerImpl.cpp @@ -896,10 +896,13 @@ void ViewerImpl::reset() m_enabled_options_count = 0; m_enabled_segments_reduced_count = 0; m_enabled_options_reduced_count = 0; + m_enabled_segments_rest_count = 0; m_shell_bitset = BitSet<>(); m_settings_used_for_ranges = std::nullopt; + delete_textures(m_enabled_segments_rest_tex_id); + delete_buffers(m_enabled_segments_rest_buf_id); delete_textures(m_enabled_options_reduced_tex_id); delete_buffers(m_enabled_options_reduced_buf_id); delete_textures(m_enabled_segments_reduced_tex_id); @@ -1162,6 +1165,11 @@ void ViewerImpl::load(GCodeInputData&& gcode_data) glsafe(glGenTextures(1, &m_enabled_options_reduced_tex_id)); glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_options_reduced_tex_id)); + glsafe(glGenBuffers(1, &m_enabled_segments_rest_buf_id)); + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_segments_rest_buf_id)); + glsafe(glGenTextures(1, &m_enabled_segments_rest_tex_id)); + glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_segments_rest_tex_id)); + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0)); glsafe(glBindTexture(GL_TEXTURE_BUFFER, old_bound_texture)); #endif // ENABLE_OPENGL_ES @@ -1182,9 +1190,9 @@ static bool is_interior_infill(EGCodeExtrusionRole role) role == EGCodeExtrusionRole::InternalBridgeInfill; } -bool ViewerImpl::reduced_set_keeps(size_t i, const PathVertex& v) const +bool ViewerImpl::reduced_set_keeps(EReducedDetailMode mode, size_t i, const PathVertex& v) const { - switch (m_settings.reduced_detail_mode) { + switch (mode) { case EReducedDetailMode::NoInternalInfill: return !is_interior_infill(v.role); case EReducedDetailMode::ShellOnly: return m_shell_bitset[i]; default: return true; @@ -1434,14 +1442,17 @@ void ViewerImpl::update_enabled_entities() #ifndef ENABLE_OPENGL_ES // ORCA: the reduced sets are filled by the same walk, so switching to them costs no rebuild. const bool build_reduced = m_settings.reduced_detail_mode != EReducedDetailMode::Off; + const bool build_rest = build_rest_set(); std::vector enabled_segments_reduced; std::vector enabled_options_reduced; + std::vector enabled_segments_rest; const uint32_t layer_stride = std::max(1, m_settings.reduced_detail_layer_stride); // Whatever else is dropped, both ends of the visible layer range are kept whole: the top is the // surface the user is looking at, and the only layer drawn at full color in top-layer-only // mode; the bottom is exposed whenever the range is cut short. const Interval& layers_range = m_layers.get_view_range(); - if (build_reduced && m_settings.reduced_detail_mode == EReducedDetailMode::ShellOnly && + if (((build_reduced && m_settings.reduced_detail_mode == EReducedDetailMode::ShellOnly) || + (build_rest && m_settings.rest_detail_mode == EReducedDetailMode::ShellOnly)) && m_shell_bitset.size != m_vertices.size()) update_shell_bitset(); #endif // ENABLE_OPENGL_ES @@ -1494,14 +1505,17 @@ void ViewerImpl::update_enabled_entities() enabled_segments.push_back(static_cast(i)); #ifndef ENABLE_OPENGL_ES + const bool whole_layer = v.layer_id == layers_range[0] || v.layer_id == layers_range[1]; + const bool keep_anyway = whole_layer || !v.is_extrusion(); + if (build_rest && !v.is_option() && (keep_anyway || reduced_set_keeps(m_settings.rest_detail_mode, i, v))) + enabled_segments_rest.push_back(static_cast(i)); if (!build_reduced) continue; - const bool whole_layer = v.layer_id == layers_range[0] || v.layer_id == layers_range[1]; if (!whole_layer && (v.layer_id % layer_stride) != 0) continue; if (v.is_option()) enabled_options_reduced.push_back(static_cast(i)); - else if (whole_layer || !v.is_extrusion() || reduced_set_keeps(i, v)) + else if (keep_anyway || reduced_set_keeps(m_settings.reduced_detail_mode, i, v)) enabled_segments_reduced.push_back(static_cast(i)); #endif // ENABLE_OPENGL_ES } @@ -1534,6 +1548,14 @@ void ViewerImpl::update_enabled_entities() m_enabled_segments_reduced_count = enabled_segments_reduced.size(); m_enabled_options_reduced_count = enabled_options_reduced.size(); + m_enabled_segments_rest_count = enabled_segments_rest.size(); + + if (build_rest) { + assert(m_enabled_segments_rest_buf_id > 0); + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_segments_rest_buf_id)); + glsafe(glBufferData(GL_TEXTURE_BUFFER, enabled_segments_rest.size() * sizeof(uint32_t), + enabled_segments_rest.empty() ? nullptr : enabled_segments_rest.data(), GL_STATIC_DRAW)); + } if (build_reduced) { assert(m_enabled_segments_reduced_buf_id > 0); @@ -1744,6 +1766,14 @@ void ViewerImpl::set_reduced_detail_layer_stride(uint32_t value) m_settings.update_enabled_entities = true; } +void ViewerImpl::set_rest_detail_mode(EReducedDetailMode mode) +{ + if (m_settings.rest_detail_mode == mode) + return; + m_settings.rest_detail_mode = mode; + m_settings.update_enabled_entities = true; +} + // ORCA: enable/disable darkening of the layers the layer slider is not scrubbed to void ViewerImpl::set_dim_previous_layers(bool value) { diff --git a/src/libvgcode/src/ViewerImpl.hpp b/src/libvgcode/src/ViewerImpl.hpp index 421e1bc7ed..a658ddc6d8 100644 --- a/src/libvgcode/src/ViewerImpl.hpp +++ b/src/libvgcode/src/ViewerImpl.hpp @@ -101,6 +101,8 @@ public: void set_reduced_detail_mode(EReducedDetailMode mode); uint32_t get_reduced_detail_layer_stride() const { return m_settings.reduced_detail_layer_stride; } void set_reduced_detail_layer_stride(uint32_t value); + EReducedDetailMode get_rest_detail_mode() const { return m_settings.rest_detail_mode; } + void set_rest_detail_mode(EReducedDetailMode mode); float get_dim_previous_layers_brightness() const { return m_settings.dim_previous_layers_brightness; } void set_dim_previous_layers_brightness(float value); @@ -507,6 +509,13 @@ private: unsigned int m_enabled_options_reduced_tex_id{ 0 }; size_t m_enabled_options_reduced_count{ 0 }; // + // OpenGL buffer to store the segments drawn at rest while Settings::rest_detail_mode is not Off. + // Every layer is drawn at rest, so the options are the full set and need no counterpart. + // + unsigned int m_enabled_segments_rest_buf_id{ 0 }; + unsigned int m_enabled_segments_rest_tex_id{ 0 }; + size_t m_enabled_segments_rest_count{ 0 }; + // // Caches for size of data sent to gpu, in bytes // size_t m_positions_tex_size{ 0 }; @@ -516,18 +525,22 @@ private: size_t m_enabled_options_tex_size{ 0 }; // The set the next draw reads from: the reduced one only while the user is dragging, and only - // if a reduced set is being built at all. + // if a reduced set is being built at all; otherwise the rest set, if one is being built. bool use_reduced_set() const { return m_settings.reduced_detail && m_settings.reduced_detail_mode != EReducedDetailMode::Off; } + bool build_rest_set() const { + return m_settings.rest_detail_mode != EReducedDetailMode::Off && m_settings.rest_detail_mode != EReducedDetailMode::LayersOnly; + } + bool use_rest_set() const { return !use_reduced_set() && build_rest_set(); } size_t active_segments_count() const { - return use_reduced_set() ? m_enabled_segments_reduced_count : m_enabled_segments_count; + return use_reduced_set() ? m_enabled_segments_reduced_count : use_rest_set() ? m_enabled_segments_rest_count : m_enabled_segments_count; } unsigned int active_segments_buf_id() const { - return use_reduced_set() ? m_enabled_segments_reduced_buf_id : m_enabled_segments_buf_id; + return use_reduced_set() ? m_enabled_segments_reduced_buf_id : use_rest_set() ? m_enabled_segments_rest_buf_id : m_enabled_segments_buf_id; } unsigned int active_segments_tex_id() const { - return use_reduced_set() ? m_enabled_segments_reduced_tex_id : m_enabled_segments_tex_id; + return use_reduced_set() ? m_enabled_segments_reduced_tex_id : use_rest_set() ? m_enabled_segments_rest_tex_id : m_enabled_segments_tex_id; } size_t active_options_count() const { return use_reduced_set() ? m_enabled_options_reduced_count : m_enabled_options_count; @@ -539,8 +552,8 @@ private: return use_reduced_set() ? m_enabled_options_reduced_tex_id : m_enabled_options_tex_id; } - // Whether the segment starting at vertex i belongs to the reduced set under the current mode - bool reduced_set_keeps(size_t i, const PathVertex& v) const; + // Whether the segment starting at vertex i belongs to the set built under the given mode + bool reduced_set_keeps(EReducedDetailMode mode, size_t i, const PathVertex& v) const; void update_shell_bitset(); #endif // ENABLE_OPENGL_ES diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index c5f79863b0..d98303d058 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1176,6 +1176,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const m_reduced_detail_while_dragging = get_app_config()->get_bool("preview_reduced_detail_while_dragging"); m_reduced_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_reduced_detail_mode")); m_reduced_detail_layer_stride = static_cast(std::max(1, std::stoi(get_app_config()->get("preview_reduced_detail_layer_stride")))); + m_rest_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_rest_detail_mode")); apply_reduced_detail_settings(); // ORCA: darken the layers the preview layer slider is not scrubbed to @@ -1924,6 +1925,13 @@ void GCodeViewer::apply_reduced_detail_settings() { m_viewer.set_reduced_detail_mode(m_reduced_detail_while_dragging ? m_reduced_detail_mode : libvgcode::EReducedDetailMode::Off); m_viewer.set_reduced_detail_layer_stride(m_reduced_detail_layer_stride); + m_viewer.set_rest_detail_mode(m_rest_detail_mode); +} + +void GCodeViewer::set_rest_detail_mode(const std::string& mode) +{ + m_rest_detail_mode = reduced_detail_mode_from_string(mode); + apply_reduced_detail_settings(); } void GCodeViewer::set_reduced_detail_while_dragging(bool value) @@ -1946,6 +1954,8 @@ void GCodeViewer::set_reduced_detail_layer_stride(unsigned int value) libvgcode::EReducedDetailMode GCodeViewer::reduced_detail_mode_from_string(const std::string& mode) { + if (mode == "full") + return libvgcode::EReducedDetailMode::Off; if (mode == "layers") return libvgcode::EReducedDetailMode::LayersOnly; if (mode == "shell") diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 2dcfb2a634..6ca3007d49 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -234,6 +234,7 @@ private: bool m_reduced_detail_while_dragging{ false }; libvgcode::EReducedDetailMode m_reduced_detail_mode{ libvgcode::EReducedDetailMode::NoInternalInfill }; unsigned int m_reduced_detail_layer_stride{ 4 }; + libvgcode::EReducedDetailMode m_rest_detail_mode{ libvgcode::EReducedDetailMode::Off }; void apply_reduced_detail_settings(); float m_legend_height; @@ -352,6 +353,8 @@ public: // the preference's string value: "layers", "no_infill" or "shell" void set_reduced_detail_mode(const std::string& mode); void set_reduced_detail_layer_stride(unsigned int value); + // what is left out even at rest: "full", "no_infill" or "shell" + void set_rest_detail_mode(const std::string& mode); static libvgcode::EReducedDetailMode reduced_detail_mode_from_string(const std::string& mode); void set_layers_z_range(const std::array& layers_z_range); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index b92d302b9a..516c231769 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -2016,6 +2016,30 @@ void PreferencesDialog::create_items() ); g_sizer->Add(item_reduced_detail_layer_stride); + auto item_rest_detail_mode = create_item_combobox( + _L("Always leave out"), + _L("What the preview leaves out at all times, dragging or not, with every layer drawn. " + "Use it when a plate of large objects is slow to draw even when the view is not moving.\n" + "Nothing: the full preview.\n" + "Internal infill: sparse and solid infill hidden inside the walls is left out.\n" + "Everything but the shell: only the toolpaths on the visible surface of the print are drawn. " + "Holes narrower than 5 mm are treated as solid."), + "preview_rest_detail_mode", + {_L("Nothing"), _L("Internal infill"), _L("Everything but the shell")}, + {"full", "no_infill", "shell"}, + // ORCA: apply the new mode immediately to the currently loaded preview + [](std::string value) { + if (Plater* plater = wxGetApp().plater()) { + if (GLCanvas3D* canvas = plater->get_preview_canvas3D()) { + canvas->get_gcode_viewer().set_rest_detail_mode(value); + canvas->set_as_dirty(); + canvas->request_extra_frame(); + } + } + } + ); + g_sizer->Add(item_rest_detail_mode); + auto item_dim_previous_layers = create_item_checkbox( _L("Dim lower layers"), _L("When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness."),