From 1ca8120398e00d37c439c32dad4994d836235750 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 30 Sep 2020 17:01:51 +0200 Subject: [PATCH] Sphere selection added as an option for painting gizmos --- src/libslic3r/TriangleSelector.cpp | 13 ++-- src/libslic3r/TriangleSelector.hpp | 7 +++ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 64 +++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 7 +++ src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 20 +++++- 6 files changed, 103 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index abbc3bc56..1462b1a76 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -35,14 +35,15 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, const Vec3f& source, const Vec3f& dir, - float radius, EnforcerBlockerType new_state) + float radius, CursorType cursor_type, + EnforcerBlockerType new_state) { assert(facet_start < m_orig_size_indices); assert(is_approx(dir.norm(), 1.f)); // Save current cursor center, squared radius and camera direction, // so we don't have to pass it around. - m_cursor = {hit, source, dir, radius*radius}; + m_cursor = {hit, source, dir, radius*radius, cursor_type}; // In case user changed cursor size since last time, update triangle edge limit. if (m_old_cursor_radius != radius) { @@ -61,7 +62,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, // add neighboring facets to list to be proccessed later for (int n=0; n<3; ++n) { int neighbor_idx = m_mesh->stl.neighbors_start[facet].neighbor[n]; - if (neighbor_idx >=0 && true/*faces_camera(neighbor_idx)*/) + if (neighbor_idx >=0 && (m_cursor.type == SPHERE || faces_camera(neighbor_idx))) facets_to_check.push_back(neighbor_idx); } } @@ -207,9 +208,11 @@ void TriangleSelector::split_triangle(int facet_idx) bool TriangleSelector::is_point_inside_cursor(const Vec3f& point) const { Vec3f diff = m_cursor.center - point; - // return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr; - return diff.squaredNorm() < m_cursor.radius_sqr; + if (m_cursor.type == CIRCLE) + return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr; + else // SPHERE + return diff.squaredNorm() < m_cursor.radius_sqr; } diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index be1b20ed4..899539c8e 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -17,6 +17,11 @@ enum class EnforcerBlockerType : int8_t; // to recursively subdivide the triangles and make the selection finer. class TriangleSelector { public: + enum CursorType { + CIRCLE, + SPHERE + }; + void set_edge_limit(float edge_limit); // Create new object on a TriangleMesh. The referenced mesh must @@ -29,6 +34,7 @@ public: const Vec3f& source, // camera position (mesh coords) const Vec3f& dir, // direction of the ray (mesh coords) float radius, // radius of the cursor + CursorType type, // current type of cursor EnforcerBlockerType new_state); // enforcer or blocker? // Get facets currently in the given state. @@ -127,6 +133,7 @@ protected: Vec3f source; Vec3f dir; float radius_sqr; + CursorType type; }; Cursor m_cursor; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6b3456b60..58346a414 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -66,7 +66,7 @@ void GLGizmoFdmSupports::on_render() const render_triangles(selection); m_c->object_clipper()->render_cut(); - render_cursor_circle(); + render_cursor(); glsafe(::glDisable(GL_BLEND)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 4b3b9e52b..e7d3e17c2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -21,6 +21,14 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic : GLGizmoBase(parent, icon_filename, sprite_id) { m_clipping_plane.reset(new ClippingPlane()); + // Make sphere and save it into a vertex buffer. + const TriangleMesh sphere_mesh = make_sphere(1., (2*M_PI)/24.); + for (size_t i=0; i(), + sphere_mesh.stl.facet_start[i].normal.cast()); + for (const stl_triangle_vertex_indices& indices : sphere_mesh.its.indices) + m_vbo_sphere.push_triangle(indices(0), indices(1), indices(2)); + m_vbo_sphere.finalize_geometry(true); } @@ -117,10 +125,18 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const } +void GLGizmoPainterBase::render_cursor() const +{ + if (m_cursor_type == TriangleSelector::SPHERE) + render_cursor_sphere(); + else + render_cursor_circle(); +} + + + void GLGizmoPainterBase::render_cursor_circle() const { - return; - const Camera& camera = wxGetApp().plater()->get_camera(); float zoom = (float)camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -164,6 +180,46 @@ void GLGizmoPainterBase::render_cursor_circle() const } +void GLGizmoPainterBase::render_cursor_sphere() const +{ + int mesh_id = m_last_mesh_idx_and_hit.first; + if (mesh_id == -1) + return; + + const Vec3f hit_pos = m_last_mesh_idx_and_hit.second; + const Selection& selection = m_parent.get_selection(); + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelVolume* mv = mo->volumes[mesh_id]; + const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; + const Transform3d instance_matrix = mi->get_transformation().get_matrix() * mv->get_matrix(); + const Transform3d instance_scaling_matrix_inverse = Geometry::Transformation(instance_matrix).get_matrix(true, true, false, true).inverse(); + const bool is_left_handed = Geometry::Transformation(instance_matrix).is_left_handed(); + + glsafe(::glPushMatrix()); + glsafe(::glMultMatrixd(instance_matrix.data())); + // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. + glsafe(::glTranslatef(hit_pos(0), hit_pos(1), hit_pos(2))); + glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius)); + + if (is_left_handed) + glFrontFace(GL_CW); + + float render_color[4] = { 0.f, 0.f, 0.f, 0.15f }; + if (m_button_down == Button::Left) + render_color[2] = 1.f; + else // right + render_color[0] = 1.f; + glsafe(::glColor4fv(render_color)); + + m_vbo_sphere.render(); + + if (is_left_handed) + glFrontFace(GL_CCW); + + glsafe(::glPopMatrix()); +} + bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point) const { @@ -354,8 +410,9 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous assert(mesh_id < int(m_triangle_selectors.size())); m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos, - dir, limit, new_state); + dir, limit, m_cursor_type, new_state); m_last_mouse_position = mouse_position; + m_last_mesh_idx_and_hit = {mesh_id, closest_hit}; } return true; @@ -392,6 +449,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous m_button_down = Button::None; m_last_mouse_position = Vec2d::Zero(); + m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()}; return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index b3e2b65f1..47bd26608 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -67,10 +67,13 @@ public: protected: void render_triangles(const Selection& selection) const; + void render_cursor() const; void render_cursor_circle() const; + void render_cursor_sphere() const; virtual void update_model_object() const = 0; virtual void update_from_model_object() = 0; void activate_internal_undo_redo_stack(bool activate); + void set_cursor_type(TriangleSelector::CursorType); float m_cursor_radius = 2.f; static constexpr float CursorRadiusMin = 0.4f; // cannot be zero @@ -80,16 +83,20 @@ protected: // For each model-part volume, store status and division of the triangles. std::vector> m_triangle_selectors; + TriangleSelector::CursorType m_cursor_type = TriangleSelector::SPHERE; + private: bool is_mesh_point_clipped(const Vec3d& point) const; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; + GLIndexedVertexArray m_vbo_sphere; bool m_internal_stack_active = false; bool m_schedule_update = false; Vec2d m_last_mouse_position = Vec2d::Zero(); + std::pair m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()}; enum class Button { None, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index d0edfba13..1b1b1f10f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -25,6 +25,7 @@ bool GLGizmoSeam::on_init() m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Cursor size") + ": "; + m_desc["cursor_type"] = _L("Cursor size") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce"] = _L("Enforce seam"); m_desc["block_caption"] = _L("Right mouse button") + " "; @@ -55,7 +56,7 @@ void GLGizmoSeam::on_render() const render_triangles(selection); m_c->object_clipper()->render_cut(); - render_cursor_circle(); + render_cursor(); glsafe(::glDisable(GL_BLEND)); } @@ -134,6 +135,23 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::EndTooltip(); } + + m_imgui->text(m_desc.at("cursor_type")); + ImGui::SameLine(/*clipping_slider_left*/); + //ImGui::PushItemWidth(window_width - clipping_slider_left); + int selection = int(m_cursor_type); + m_imgui->combo(" ", {"Circle", "Sphere"}, selection); + m_cursor_type = TriangleSelector::CursorType(selection); + /*if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + }*/ + + + ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) m_imgui->text(m_desc.at("clipping_of_view"));