diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index dcb2d2338..9a29789d3 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -169,6 +169,7 @@ namespace ImGui const wchar_t LegendCOG = 0x2615; const wchar_t LegendShells = 0x2616; const wchar_t LegendToolMarker = 0x2617; + const wchar_t WarningMarkerSmall = 0x2618; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 6a8a99856..58eb19a04 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -19,6 +19,8 @@ #include "libslic3r/Model.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" +#include "imgui/imgui_internal.h" + namespace Slic3r { namespace GUI { @@ -39,7 +41,7 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, m_group_id = 3; m_connectors_group_id = 4; - m_modes = { _u8L("Planar"), _u8L("Grid") + m_modes = { _u8L("Planar")//, _u8L("Grid") // , _u8L("Radial"), _u8L("Modular") }; @@ -471,6 +473,8 @@ void GLGizmoCut3D::render_cut_plane() void GLGizmoCut3D::render_cut_center_graber() { + ::glDisable(GL_DEPTH_TEST); + Slic3r::ScopeGuard guard([]() { ::glEnable(GL_DEPTH_TEST); }); const Vec3d& angles = m_rotation_gizmo.get_rotation(); m_grabbers[0].angles = angles; m_grabbers[0].color = GRABBER_COLOR; @@ -878,9 +882,13 @@ void GLGizmoCut3D::on_render() render_connectors(false); + if (! m_connectors_editing) + ::glDisable(GL_DEPTH_TEST); m_c->object_clipper()->render_cut(); + if (! m_connectors_editing) + ::glEnable(GL_DEPTH_TEST); - if (!m_hide_cut_plane) { + if (!m_hide_cut_plane && ! m_connectors_editing) { render_cut_center_graber(); render_cut_plane(); if (m_hover_id < m_group_id && m_mode == size_t(CutMode::cutPlanar) && !cut_line_processing()) @@ -922,146 +930,175 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit) last_y = y; } - render_combo(_u8L("Mode"), m_modes, m_mode); - - bool revert_rotation{ false }; - bool revert_move{ false }; + // render_combo(_u8L("Mode"), m_modes, m_mode); CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + bool cut_clicked = false; + bool revert_move{ false }; + bool revert_rotation{ false }; - if (m_mode == size_t(CutMode::cutPlanar)) { - ImGui::AlignTextToFramePadding(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Hold SHIFT key and connect some two points of an object to cut by line")); - ImGui::Separator(); + if (! m_connectors_editing) { + if (m_mode == size_t(CutMode::cutPlanar)) { + ImGui::AlignTextToFramePadding(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Hold SHIFT key and connect some two points of an object to cut by line")); + ImGui::Separator(); - ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Move center")); + //////// + double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; + std::string unit_str = m_imperial_units ? _u8L("inch") : _u8L("mm"); + const BoundingBoxf3 tbb = transformed_bounding_box(); + double top = (tbb.min.z() <= 0.0 ? tbb.max.z() : tbb.size().z()) * koef; + double bottom = (tbb.max.z() <= 0.0 ? tbb.size().z() : (tbb.min.z() * (-1))) * koef; + + //static float v = 0.; // TODO: connect to cutting plane position + m_imgui->text(_L("Cut position: ")); + render_move_center_input(Z); + //m_imgui->input_double(unit_str, v); + //v = std::clamp(v, 0.f, float(bottom+top)); + if (m_imgui->button("Reset cutting plane")) { + // TODO: reset both position and rotation + } + ////// - m_imgui->disabled_begin(m_plane_center == bounding_box().center()); - revert_move = render_revert_button("move"); - m_imgui->disabled_end(); + // ImGui::AlignTextToFramePadding(); + // m_imgui->text(_L("Move center")); - for (Axis axis : {X, Y, Z}) - render_move_center_input(axis); - m_imgui->text(m_imperial_units ? _L("in") : _L("mm")); + // m_imgui->disabled_begin(m_plane_center == bounding_box().center()); + // revert_move = render_revert_button("move"); + // m_imgui->disabled_end(); - ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Rotation")); + // for (Axis axis : {X, Y, Z}) + // render_move_center_input(axis); + // m_imgui->text(m_imperial_units ? _L("in") : _L("mm")); - m_imgui->disabled_begin(m_rotation_gizmo.get_rotation() == Vec3d::Zero()); - revert_rotation = render_revert_button("rotation"); - m_imgui->disabled_end(); + // ImGui::AlignTextToFramePadding(); + // m_imgui->text(_L("Rotation")); - for (Axis axis : {X, Y, Z}) - render_rotation_input(axis); - m_imgui->text(_L("°")); + // m_imgui->disabled_begin(m_rotation_gizmo.get_rotation() == Vec3d::Zero()); + // revert_rotation = render_revert_button("rotation"); + // m_imgui->disabled_end(); + + // for (Axis axis : {X, Y, Z}) + // render_rotation_input(axis); + // m_imgui->text(_L("°")); + + // ImGui::Separator(); + + // double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; + // wxString unit_str = " " + (m_imperial_units ? _L("in") : _L("mm")); + + // Vec3d tbb_sz = transformed_bounding_box().size(); + // wxString size = "X: " + double_to_string(tbb_sz.x() * koef, 2) + unit_str + + // ", Y: " + double_to_string(tbb_sz.y() * koef, 2) + unit_str + + // ", Z: " + double_to_string(tbb_sz.z() * koef, 2) + unit_str; + + // ImGui::AlignTextToFramePadding(); + // m_imgui->text(_L("Build size")); + // ImGui::SameLine(m_label_width); + // m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, size); + } + + if (m_mode == size_t(CutMode::cutPlanar)) { + ImGui::Separator(); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("After cut") + ": "); + bool keep = true; + + ImGui::SameLine(m_label_width); + m_imgui->text(_L("Upper part")); + ImGui::SameLine(2 * m_label_width); + + m_imgui->disabled_begin(!connectors.empty()); + m_imgui->checkbox(_L("Keep") + "##upper", connectors.empty() ? m_keep_upper : keep); + m_imgui->disabled_end(); + ImGui::SameLine(); + m_imgui->disabled_begin(!m_keep_upper); + m_imgui->disabled_begin(is_approx(m_rotation_gizmo.get_rotation().x(), 0.) && is_approx(m_rotation_gizmo.get_rotation().y(), 0.)); + m_imgui->checkbox(_L("Place on cut") + "##upper", m_rotate_upper); + m_imgui->disabled_end(); + m_imgui->disabled_end(); + + m_imgui->text(""); + ImGui::SameLine(m_label_width); + m_imgui->text(_L("Lower part")); + ImGui::SameLine(2 * m_label_width); + + m_imgui->disabled_begin(!connectors.empty()); + m_imgui->checkbox(_L("Keep") + "##lower", connectors.empty() ? m_keep_lower : keep); + m_imgui->disabled_end(); + ImGui::SameLine(); + m_imgui->disabled_begin(!m_keep_lower); + m_imgui->checkbox(_L("Place on cut") + "##lower", m_rotate_lower); + m_imgui->disabled_end(); + } ImGui::Separator(); - double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; - wxString unit_str = " " + (m_imperial_units ? _L("in") : _L("mm")); - - Vec3d tbb_sz = transformed_bounding_box().size(); - wxString size = "X: " + double_to_string(tbb_sz.x() * koef, 2) + unit_str + - ", Y: " + double_to_string(tbb_sz.y() * koef, 2) + unit_str + - ", Z: " + double_to_string(tbb_sz.z() * koef, 2) + unit_str; - - ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Build size")); - ImGui::SameLine(m_label_width); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, size); - } - - m_imgui->disabled_begin(!m_keep_lower || !m_keep_upper); - // Connectors section - ImGui::Separator(); - - ImGui::AlignTextToFramePadding(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Connectors")); - - m_imgui->disabled_begin(connectors.empty()); - ImGui::SameLine(m_label_width); - if (m_imgui->button(" " + _L("Reset") + " ##connectors")) - reset_connectors(); - m_imgui->disabled_end(); - - m_imgui->text(_L("Mode")); - render_connect_mode_radio_button(CutConnectorMode::Auto); - render_connect_mode_radio_button(CutConnectorMode::Manual); - - m_imgui->text(_L("Type")); - render_connect_type_radio_button(CutConnectorType::Plug); - render_connect_type_radio_button(CutConnectorType::Dowel); - - if (render_combo(_u8L("Style"), m_connector_styles, m_connector_style)) - update_connector_shape(); - if (render_combo(_u8L("Shape"), m_connector_shapes, m_connector_shape_id)) - update_connector_shape(); - - if (render_double_input(_u8L("Depth ratio"), m_connector_depth_ratio)) - for (auto& connector : connectors) - connector.height = float(m_connector_depth_ratio); - if (render_double_input(_u8L("Size"), m_connector_size)) - for (auto& connector : connectors) - connector.radius = float(m_connector_size * 0.5); - - m_imgui->disabled_end(); - - if (m_mode == size_t(CutMode::cutPlanar)) { + if (m_imgui->button(_L("Add/Edit connectors"))) + m_connectors_editing = true; + } else { // connectors mode + m_imgui->disabled_begin(!m_keep_lower || !m_keep_upper); + // Connectors section ImGui::Separator(); ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("After cut") + ": "); - bool keep = true; + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Connectors")); + m_imgui->disabled_begin(connectors.empty()); ImGui::SameLine(m_label_width); - m_imgui->text(_L("Upper part")); - ImGui::SameLine(2 * m_label_width); - - m_imgui->disabled_begin(!connectors.empty()); - m_imgui->checkbox(_L("Keep") + "##upper", connectors.empty() ? m_keep_upper : keep); - m_imgui->disabled_end(); - ImGui::SameLine(); - m_imgui->disabled_begin(!m_keep_upper); - m_imgui->checkbox(_L("Flip") + "##upper", m_rotate_upper); + if (m_imgui->button(" " + _L("Reset") + " ##connectors")) + reset_connectors(); m_imgui->disabled_end(); - m_imgui->text(""); - ImGui::SameLine(m_label_width); - m_imgui->text(_L("Lower part")); - ImGui::SameLine(2 * m_label_width); + m_imgui->text(_L("Mode")); + render_connect_mode_radio_button(CutConnectorMode::Auto); + render_connect_mode_radio_button(CutConnectorMode::Manual); + + m_imgui->text(_L("Type")); + render_connect_type_radio_button(CutConnectorType::Plug); + render_connect_type_radio_button(CutConnectorType::Dowel); + + if (render_combo(_u8L("Style"), m_connector_styles, m_connector_style)) + update_connector_shape(); + if (render_combo(_u8L("Shape"), m_connector_shapes, m_connector_shape_id)) + update_connector_shape(); + + if (render_double_input(_u8L("Depth ratio"), m_connector_depth_ratio)) + for (auto& connector : connectors) + connector.height = float(m_connector_depth_ratio); + if (render_double_input(_u8L("Size"), m_connector_size)) + for (auto& connector : connectors) + connector.radius = float(m_connector_size * 0.5); - m_imgui->disabled_begin(!connectors.empty()); - m_imgui->checkbox(_L("Keep") + "##lower", connectors.empty() ? m_keep_lower : keep); - m_imgui->disabled_end(); - ImGui::SameLine(); - m_imgui->disabled_begin(!m_keep_lower); - m_imgui->checkbox(_L("Flip") + "##lower", m_rotate_lower); m_imgui->disabled_end(); + + if (m_imgui->button(_L("Confirm connectors"))) + m_connectors_editing = false; } ImGui::Separator(); + m_imgui->text(m_has_invalid_connector ? wxString(ImGui::WarningMarkerSmall) + _L("Invalid connectors detected.") : wxString()); m_imgui->disabled_begin(!can_perform_cut()); - const bool cut_clicked = m_imgui->button(_L("Perform cut")); + cut_clicked = m_imgui->button(_L("Perform cut")); m_imgui->disabled_end(); - ImGui::Separator(); - - m_imgui->checkbox(_L("Hide cut plane and grabbers"), m_hide_cut_plane); + m_imgui->end(); //////// - static bool hide_clipped = true; - static bool fill_cut = true; - static float contour_width = 0.2f; + m_imgui->begin(wxString("DEBUG")); + static bool hide_clipped = false; + static bool fill_cut = false; + static float contour_width = 0.4f; + m_imgui->checkbox(_L("Hide cut plane and grabbers"), m_hide_cut_plane); if (m_imgui->checkbox("hide_clipped", hide_clipped) && !hide_clipped) m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); m_imgui->checkbox("fill_cut", fill_cut); m_imgui->slider_float("contour_width", &contour_width, 0.f, 3.f); - m_c->object_clipper()->set_behavior(hide_clipped, fill_cut, contour_width); - //////// - + m_c->object_clipper()->set_behavior(hide_clipped || m_connectors_editing, fill_cut || m_connectors_editing, contour_width); m_imgui->end(); + //////// if (cut_clicked && (m_keep_upper || m_keep_lower)) perform_cut(m_parent.get_selection()); @@ -1101,10 +1138,16 @@ Transform3d GLGizmoCut3D::get_volume_transformation(const ModelVolume* volume) c void GLGizmoCut3D::render_connectors(bool picking) { - if (cut_line_processing() || m_connector_mode == CutConnectorMode::Auto || !m_c->selection_info()) + if (picking && ! m_connectors_editing) return; - m_has_invalid_connector = false; + const bool depth_test = m_connectors_editing; + if (! depth_test) + ::glDisable(GL_DEPTH_TEST); + Slic3r::ScopeGuard guard_depth_test([&](){ if (! depth_test) ::glEnable(GL_DEPTH_TEST); }); + + if (cut_line_processing() || m_connector_mode == CutConnectorMode::Auto || !m_c->selection_info()) + return; const ModelObject* mo = m_c->selection_info()->model_object(); auto inst_id = m_c->selection_info()->get_active_instance(); @@ -1150,6 +1193,8 @@ void GLGizmoCut3D::render_connectors(bool picking) const Transform3d instance_trafo = Geometry::assemble_transform(Vec3d(0.0, 0.0, sla_shift)) * mi->get_transformation().get_matrix(); + m_has_invalid_connector = false; + for (size_t i = 0; i < connectors.size(); ++i) { const CutConnector& connector = connectors[i]; // const bool& point_selected = m_selected[i]; @@ -1180,13 +1225,12 @@ void GLGizmoCut3D::render_connectors(bool picking) const Transform3d volume_trafo = get_volume_transformation(mv); if (m_c->raycaster()->raycasters()[mesh_id]->is_valid_intersection(pos, -normal, instance_trafo * volume_trafo)) { - render_color = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); + render_color = m_connectors_editing ? ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f) : ColorRGBA(0.5f, 0.5f, 0.5f, 1.f); break; } render_color = ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f); - } - if (!m_has_invalid_connector && render_color == ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f)) m_has_invalid_connector = true; + } } } @@ -1330,7 +1374,7 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair const Transform3d volume_trafo = get_volume_transformation(mv); m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * volume_trafo, - camera, hit, normal, m_c->object_clipper()->get_clipping_plane(), + camera, hit, normal, m_c->object_clipper()->get_clipping_plane(true), nullptr, &clipping_plane_was_hit); if (clipping_plane_was_hit) { // recalculate hit to object's local position @@ -1431,14 +1475,14 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi if (is_dragging() || m_connector_mode == CutConnectorMode::Auto || (!m_keep_upper || !m_keep_lower)) return false; - if ( m_hover_id < 0 && shift_down && + if ( m_hover_id < 0 && shift_down && ! m_connectors_editing && (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::Moving) ) return process_cut_line(action, mouse_position); CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; // left down without selection rectangle - place connector on the cut plane: - if (action == SLAGizmoEventType::LeftDown && /*!m_selection_rectangle.is_dragging() && */!shift_down) { + if (action == SLAGizmoEventType::LeftDown && /*!m_selection_rectangle.is_dragging() && */!shift_down && m_connectors_editing) { // If any point is in hover state, this should initiate its move - return control back to GLCanvas: if (m_hover_id != -1) return false; @@ -1465,7 +1509,7 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi } return true; } - else if (action == SLAGizmoEventType::RightDown && !shift_down) { + else if (action == SLAGizmoEventType::RightDown && !shift_down && m_connectors_editing) { // If any point is in hover state, this should initiate its move - return control back to GLCanvas: if (m_hover_id < m_connectors_group_id) return false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 439abea8d..dfaef3fb2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -57,6 +57,7 @@ class GLGizmoCut3D : public GLGizmoBase bool m_rotate_lower{ false }; bool m_hide_cut_plane{ false }; + bool m_connectors_editing{ false }; double m_connector_depth_ratio{ 3.0 }; double m_connector_size{ 2.5 }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index e7ba37010..c28fe6356 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -475,10 +475,10 @@ void ObjectClipper::set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset get_pool()->get_canvas()->set_as_dirty(); } -const ClippingPlane* ObjectClipper::get_clipping_plane() const +const ClippingPlane* ObjectClipper::get_clipping_plane(bool ignore_hide_clipped) const { static const ClippingPlane no_clip = ClippingPlane::ClipsNothing(); - return m_hide_clipped ? m_clp.get() : &no_clip; + return (ignore_hide_clipped || m_hide_clipped) ? m_clp.get() : &no_clip; } void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contour_width) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index efd3b436e..72df620cf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -257,7 +257,7 @@ public: void set_normal(const Vec3d& dir); double get_position() const { return m_clp_ratio; } - const ClippingPlane* get_clipping_plane() const; + const ClippingPlane* get_clipping_plane(bool ignore_hide_clipped = false) const; void render_cut() const; void set_position_by_ratio(double pos, bool keep_normal); void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 65b292c25..ff084b0a4 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -76,6 +76,7 @@ static const std::map font_icons = { {ImGui::LegendToolMarker , "legend_toolmarker" }, #endif // ENABLE_LEGEND_TOOLBAR_ICONS {ImGui::RevertButton , "undo" }, + {ImGui::WarningMarkerSmall , "notification_warning" }, }; static const std::map font_icons_large = {