diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index 09003f407..dce033d7b 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -1,6 +1,21 @@ #version 110 const vec3 ZERO = vec3(0.0, 0.0, 0.0); +const vec3 GREEN = vec3(0.0, 0.7, 0.0); +const vec3 YELLOW = vec3(0.5, 0.7, 0.0); +const vec3 RED = vec3(0.7, 0.0, 0.0); +const float EPSILON = 0.0001; + +struct SlopeDetection +{ + bool active; + // x = yellow, y = red + vec2 z_range; + mat3 volume_world_normal_matrix; +}; + +uniform vec4 uniform_color; +uniform SlopeDetection slope; varying vec3 clipping_planes_dots; @@ -10,14 +25,20 @@ varying vec2 intensity; varying vec3 delta_box_min; varying vec3 delta_box_max; -uniform vec4 uniform_color; +varying float world_normal_z; +vec3 slope_color() +{ + float gradient_range = slope.z_range.x - slope.z_range.y; + return (world_normal_z > slope.z_range.x - EPSILON) ? GREEN : ((gradient_range == 0.0) ? RED : mix(RED, YELLOW, clamp((world_normal_z - slope.z_range.y) / gradient_range, 0.0, 1.0))); +} void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; + vec3 color = slope.active ? slope_color() : uniform_color.rgb; // if the fragment is outside the print volume -> use darker color - vec3 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(uniform_color.rgb, ZERO, 0.3333) : uniform_color.rgb; + color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); } diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index cc54c1c44..72d6c18b3 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -20,13 +20,22 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0); struct PrintBoxDetection { + bool active; vec3 min; vec3 max; - bool volume_detection; mat4 volume_world_matrix; }; +struct SlopeDetection +{ + bool active; + // x = yellow, y = red + vec2 z_range; + mat3 volume_world_normal_matrix; +}; + uniform PrintBoxDetection print_box; +uniform SlopeDetection slope; // Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. uniform vec2 z_range; @@ -41,6 +50,8 @@ varying vec3 delta_box_max; varying vec3 clipping_planes_dots; +varying float world_normal_z; + void main() { // First transform the normal into camera space and normalize the result. @@ -61,7 +72,7 @@ void main() intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // compute deltas for out of print volume detection (world coordinates) - if (print_box.volume_detection) + if (print_box.active) { vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz; delta_box_min = v - print_box.min; @@ -73,6 +84,9 @@ void main() delta_box_max = ZERO; } + // z component of normal vector in world coordinate used for slope shading + world_normal_z = slope.active ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; + gl_Position = ftransform(); // Point in homogenous coordinates. vec4 world_pos = print_box.volume_world_matrix * gl_Vertex; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index c6c6ce45c..31f65f7ac 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,6 +44,13 @@ // Enable fix for dragging mouse event handling for gizmobar #define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL) +//============ +// 2.3.0 techs +//============ +#define ENABLE_2_3_0 1 + +// Enable rendering of objects colored by facets' slope +#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_2_0) //=================== // 2.3.0.alpha1 techs diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a4e5949a0..c13c1b937 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -394,6 +394,7 @@ void GLVolume::render() const glFrontFace(GL_CCW); } +#if !ENABLE_SLOPE_RENDERING void GLVolume::render(int color_id, int detection_id, int worldmatrix_id) const { if (color_id >= 0) @@ -409,6 +410,7 @@ void GLVolume::render(int color_id, int detection_id, int worldmatrix_id) const render(); } +#endif // !ENABLE_SLOPE_RENDERING bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); } bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); } @@ -650,28 +652,64 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; GLint z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "z_range") : -1; GLint clipping_plane_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "clipping_plane") : -1; + GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1; GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1; - GLint print_box_detection_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1; + GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.active") : -1; GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1; + +#if ENABLE_SLOPE_RENDERING + GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.active") : -1; + GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1; + GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1; +#endif // ENABLE_SLOPE_RENDERING glcheck(); if (print_box_min_id != -1) - glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min)); + glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)m_print_box_min)); if (print_box_max_id != -1) - glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max)); + glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)m_print_box_max)); if (z_range_id != -1) - glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range)); + glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)m_z_range)); if (clipping_plane_id != -1) - glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)clipping_plane)); + glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)m_clipping_plane)); + +#if ENABLE_SLOPE_RENDERING + if (slope_z_range_id != -1) + glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope.z_range.data())); +#endif // ENABLE_SLOPE_RENDERING GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); for (GLVolumeWithIdAndZ& volume : to_render) { volume.first->set_render_color(); +#if ENABLE_SLOPE_RENDERING + if (color_id >= 0) + glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)volume.first->render_color)); + else + glsafe(::glColor4fv(volume.first->render_color)); + + if (print_box_active_id != -1) + glsafe(::glUniform1i(print_box_active_id, volume.first->shader_outside_printer_detection_enabled ? 1 : 0)); + + if (print_box_worldmatrix_id != -1) + glsafe(::glUniformMatrix4fv(print_box_worldmatrix_id, 1, GL_FALSE, (const GLfloat*)volume.first->world_matrix().cast().data())); + + if (slope_active_id != -1) + glsafe(::glUniform1i(slope_active_id, m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower ? 1 : 0)); + + if (slope_normal_matrix_id != -1) + { + Matrix3f normal_matrix = volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast(); + glsafe(::glUniformMatrix3fv(slope_normal_matrix_id, 1, GL_FALSE, (const GLfloat*)normal_matrix.data())); + } + + volume.first->render(); +#else volume.first->render(color_id, print_box_detection_id, print_box_worldmatrix_id); +#endif // ENABLE_SLOPE_RENDERING } glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); @@ -1887,7 +1925,16 @@ void GLModel::render() const GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; glcheck(); +#if ENABLE_SLOPE_RENDERING + if (color_id >= 0) + glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)m_volume.render_color)); + else + glsafe(::glColor4fv(m_volume.render_color)); + + m_volume.render(); +#else m_volume.render(color_id, -1, -1); +#endif // ENABLE_SLOPE_RENDERING glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e4cd7eb47..70d6fb016 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -445,7 +445,9 @@ public: void set_range(double low, double high); void render() const; +#if !ENABLE_SLOPE_RENDERING void render(int color_id, int detection_id, int worldmatrix_id) const; +#endif // !ENABLE_SLOPE_RENDERING void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } @@ -481,20 +483,36 @@ public: private: // min and max vertex of the print box volume - float print_box_min[3]; - float print_box_max[3]; + float m_print_box_min[3]; + float m_print_box_max[3]; // z range for clipping in shaders - float z_range[2]; + float m_z_range[2]; // plane coeffs for clipping in shaders - float clipping_plane[4]; + float m_clipping_plane[4]; + +#if ENABLE_SLOPE_RENDERING + struct Slope + { + // toggle for slope rendering + bool active{ false }; + // [0] = yellow, [1] = red + std::array z_range; + }; + + Slope m_slope; +#endif // ENABLE_SLOPE_RENDERING public: GLVolumePtrs volumes; - GLVolumeCollection() {}; - ~GLVolumeCollection() { clear(); }; +#if ENABLE_SLOPE_RENDERING + GLVolumeCollection() { set_default_slope_z_range(); } +#else + GLVolumeCollection() = default; +#endif // ENABLE_SLOPE_RENDERING + ~GLVolumeCollection() { clear(); } std::vector load_object( const ModelObject *model_object, @@ -545,12 +563,21 @@ public: void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) { - print_box_min[0] = min_x; print_box_min[1] = min_y; print_box_min[2] = min_z; - print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z; + m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z; + m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z; } - void set_z_range(float min_z, float max_z) { z_range[0] = min_z; z_range[1] = max_z; } - void set_clipping_plane(const double* coeffs) { clipping_plane[0] = coeffs[0]; clipping_plane[1] = coeffs[1]; clipping_plane[2] = coeffs[2]; clipping_plane[3] = coeffs[3]; } + void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; } + void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; } + +#if ENABLE_SLOPE_RENDERING + bool is_slope_active() const { return m_slope.active; } + void set_slope_active(bool active) { m_slope.active = active; } + + const std::array& get_slope_z_range() const { return m_slope.z_range; } + void set_slope_z_range(const std::array& range) { m_slope.z_range = range; } + void set_default_slope_z_range() { m_slope.z_range = { -::cos(Geometry::deg2rad(90.0f - 45.0f)), -::cos(Geometry::deg2rad(90.0f - 70.0f)) }; } +#endif // ENABLE_SLOPE_RENDERING // returns true if all the volumes are completely contained in the print volume // returns the containment state in the given out_state, if non-null diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index cfd5e1e11..c2713c80d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1445,6 +1445,62 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas } #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI +#if ENABLE_SLOPE_RENDERING +void GLCanvas3D::Slope::render() const +{ + if (is_shown()) + { + const std::array& z_range = m_volumes.get_slope_z_range(); + std::array angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f }; + bool modified = false; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + const Size& cnv_size = m_canvas.get_canvas_size(); + imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f); + imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + imgui.text(_(L("Facets' normal angle range (degrees)")) + ":"); + + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f)); + if (ImGui::SliderFloat("##yellow", &angle_range[0], 0.0f, 90.0f, "%.1f")) + { + modified = true; + if (angle_range[1] < angle_range[0]) + angle_range[1] = angle_range[0]; + } + ImGui::PopStyleColor(4); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f)); + if (ImGui::SliderFloat("##red", &angle_range[1], 0.0f, 90.0f, "%.1f")) + { + modified = true; + if (angle_range[0] > angle_range[1]) + angle_range[0] = angle_range[1]; + } + ImGui::PopStyleColor(4); + + ImGui::Separator(); + + if (imgui.button(_(L("Default")))) + m_volumes.set_default_slope_z_range(); + + // to let the dialog immediately showup without waiting for a mouse move + if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowExpectedSize(ImGui::GetCurrentWindow()).x) + m_canvas.request_extra_frame(); + + imgui.end(); + + if (modified) + m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - angle_range[0])), -::cos(Geometry::deg2rad(90.0f - angle_range[1])) }); + } + } +#endif // ENABLE_SLOPE_RENDERING + wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); @@ -1519,6 +1575,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar #endif // ENABLE_RENDER_PICKING_PASS , m_render_sla_auxiliaries(true) , m_labels(*this) +#if ENABLE_SLOPE_RENDERING + , m_slope(*this, m_volumes) +#endif // ENABLE_SLOPE_RENDERING { if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); @@ -1838,6 +1897,11 @@ bool GLCanvas3D::is_reload_delayed() const void GLCanvas3D::enable_layers_editing(bool enable) { +#if ENABLE_SLOPE_RENDERING + if (enable && m_slope.is_shown()) + m_slope.show(false); +#endif // ENABLE_SLOPE_RENDERING + m_layers_editing.set_enabled(enable); const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); for (unsigned int idx : idxs) @@ -3022,6 +3086,17 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } case 'B': case 'b': { zoom_to_bed(); break; } +#if ENABLE_SLOPE_RENDERING + case 'D': + case 'd': { + if (!is_layers_editing_enabled()) + { + m_slope.show(!m_slope.is_shown()); + m_dirty = true; + } + break; + } +#endif // ENABLE_SLOPE_RENDERING case 'E': case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; } case 'I': @@ -5413,6 +5488,10 @@ void GLCanvas3D::_render_overlays() const } m_labels.render(sorted_instances); +#if ENABLE_SLOPE_RENDERING + m_slope.render(); +#endif // ENABLE_SLOPE_RENDERING + glsafe(::glPopMatrix()); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 3949d5a43..952f45c39 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -406,6 +406,24 @@ private: }; #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI +#if ENABLE_SLOPE_RENDERING + class Slope + { + bool m_enabled{ false }; + GLCanvas3D& m_canvas; + GLVolumeCollection& m_volumes; + + public: + Slope(GLCanvas3D& canvas, GLVolumeCollection& volumes) : m_canvas(canvas), m_volumes(volumes) {} + + void enable(bool enable) { m_enabled = enable; } + bool is_enabled() const { return m_enabled; } + void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); } + bool is_shown() const { return m_volumes.is_slope_active(); } + void render() const; + }; +#endif // ENABLE_SLOPE_RENDERING + public: enum ECursorType : unsigned char { @@ -489,6 +507,9 @@ private: #if ENABLE_CANVAS_TOOLTIP_USING_IMGUI mutable Tooltip m_tooltip; #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI +#if ENABLE_SLOPE_RENDERING + Slope m_slope; +#endif // ENABLE_SLOPE_RENDERING public: #if ENABLE_NON_STATIC_CANVAS_MANAGER @@ -579,6 +600,9 @@ public: void enable_undoredo_toolbar(bool enable); void enable_dynamic_background(bool enable); void enable_labels(bool enable) { m_labels.enable(enable); } +#if ENABLE_SLOPE_RENDERING + void enable_slope(bool enable) { m_slope.enable(enable); } +#endif // ENABLE_SLOPE_RENDERING void allow_multisample(bool allow); void zoom_to_bed(); @@ -702,6 +726,11 @@ public: bool are_labels_shown() const { return m_labels.is_shown(); } void show_labels(bool show) { m_labels.show(show); } +#if ENABLE_SLOPE_RENDERING + bool is_slope_shown() const { return m_slope.is_shown(); } + void show_slope(bool show) { m_slope.show(show); } +#endif // ENABLE_SLOPE_RENDERING + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index d94cba974..29ece9b31 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -98,6 +98,9 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_ m_canvas->enable_main_toolbar(true); m_canvas->enable_undoredo_toolbar(true); m_canvas->enable_labels(true); +#if ENABLE_SLOPE_RENDERING + m_canvas->enable_slope(true); +#endif // ENABLE_SLOPE_RENDERING wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 842cec5e2..d05ecbcd8 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -145,6 +145,9 @@ void KBShortcutsDialog::fill_shortcuts() // View { "0-6", L("Camera view") }, { "E", L("Show/Hide object/instance labels") }, +#if ENABLE_SLOPE_RENDERING + { "D", L("Turn On/Off facets' slope rendering") }, +#endif // ENABLE_SLOPE_RENDERING // Configuration { ctrl + "P", L("Preferences") }, // Help diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index abd1891d3..60167bd17 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -764,9 +764,20 @@ void MainFrame::init_menubar() append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + sep + "&6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); }, "", nullptr, [this](){return can_change_view(); }, this); viewMenu->AppendSeparator(); +#if ENABLE_SLOPE_RENDERING + wxMenu* options_menu = new wxMenu(); + append_menu_check_item(options_menu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")), + [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, + [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); + append_menu_check_item(options_menu, wxID_ANY, _(L("Show &slope")) + sep + "D", _(L("Objects coloring using faces' slope")), + [this](wxCommandEvent&) { m_plater->show_view3D_slope(!m_plater->is_view3D_slope_shown()); }, this, + [this]() { return m_plater->is_view3D_shown() && !m_plater->is_view3D_layers_editing_enabled(); }, [this]() { return m_plater->is_view3D_slope_shown(); }, this); + append_submenu(viewMenu, options_menu, wxID_ANY, _(L("&Options")), ""); +#else append_menu_check_item(viewMenu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")), [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); +#endif // ENABLE_SLOPE_RENDERING } // Help menu diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c103f8da9..67b63d8ad 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1823,6 +1823,13 @@ struct Plater::priv bool are_view3D_labels_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->are_labels_shown(); } void show_view3D_labels(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_labels(show); } +#if ENABLE_SLOPE_RENDERING + bool is_view3D_slope_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_slope_shown(); } + void show_view3D_slope(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_slope(show); } + + bool is_view3D_layers_editing_enabled() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_layers_editing_enabled(); } +#endif // ENABLE_SLOPE_RENDERING + void set_current_canvas_as_dirty(); GLCanvas3D* get_current_canvas3D(); #if ENABLE_NON_STATIC_CANVAS_MANAGER @@ -4674,6 +4681,13 @@ bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); } bool Plater::are_view3D_labels_shown() const { return p->are_view3D_labels_shown(); } void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); } +#if ENABLE_SLOPE_RENDERING +bool Plater::is_view3D_slope_shown() const { return p->is_view3D_slope_shown(); } +void Plater::show_view3D_slope(bool show) { p->show_view3D_slope(show); } + +bool Plater::is_view3D_layers_editing_enabled() const { return p->is_view3D_layers_editing_enabled(); } +#endif // ENABLE_SLOPE_RENDERING + void Plater::select_all() { p->select_all(); } void Plater::deselect_all() { p->deselect_all(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 4462d4237..a1ce52389 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -175,6 +175,13 @@ public: bool are_view3D_labels_shown() const; void show_view3D_labels(bool show); +#if ENABLE_SLOPE_RENDERING + bool is_view3D_slope_shown() const; + void show_view3D_slope(bool show); + + bool is_view3D_layers_editing_enabled() const; +#endif // ENABLE_SLOPE_RENDERING + // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. void update_ui_from_settings();