diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 4fa51c486..ac103615a 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -39,6 +39,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmosCommon.hpp GUI/Gizmos/GLGizmoBase.cpp GUI/Gizmos/GLGizmoBase.hpp + GUI/Gizmos/GLGizmoSlaBase.cpp + GUI/Gizmos/GLGizmoSlaBase.hpp GUI/Gizmos/GLGizmoEmboss.cpp GUI/Gizmos/GLGizmoEmboss.hpp GUI/Gizmos/GLGizmoMove.cpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index e8889b39d..633e61e56 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -1,6 +1,6 @@ +#include "libslic3r/libslic3r.h" #include "GLGizmoHollow.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include @@ -17,10 +17,8 @@ namespace Slic3r { namespace GUI { -static const ColorRGBA DISABLED_COLOR = ColorRGBA::DARK_GRAY(); - GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) + : GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposAssembly) { } @@ -58,7 +56,7 @@ void GLGizmoHollow::data_changed() const SLAPrintObject* po = m_c->selection_info()->print_object(); if (po != nullptr && po->get_mesh_to_print().empty()) - process_mesh(slaposAssembly); + reslice_until_step(slaposAssembly); update_volumes(); @@ -265,25 +263,6 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) #endif // !ENABLE_LEGACY_OPENGL_REMOVAL } -void GLGizmoHollow::render_volumes() -{ - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_clip"); - if (shader == nullptr) - return; - - shader->start_using(); - shader->set_uniform("emission_factor", 0.0f); - const Camera& camera = wxGetApp().plater()->get_camera(); - - ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane(); - clipping_plane.set_normal(-clipping_plane.get_normal()); - m_volumes.set_clipping_plane(clipping_plane.get_data()); - - m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix()); - shader->stop_using(); - -} - bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const { if (m_c->object_clipper()->get_position() == 0.) @@ -299,34 +278,6 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); } - - -// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal -// Return false if no intersection was found, true otherwise. -bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) -{ - if (m_c->raycaster()->raycasters().size() != 1) - return false; - if (! m_c->raycaster()->raycaster()) - return false; - - // The raycaster query - Vec3f hit; - Vec3f normal; - if (m_c->raycaster()->raycaster()->unproject_on_mesh( - mouse_pos, - m_volumes.volumes.front()->world_matrix(), - wxGetApp().plater()->get_camera(), - hit, - normal, - m_c->object_clipper()->get_position() != 0.0 ? m_c->object_clipper()->get_clipping_plane() : nullptr)) { - // Return both the point and the facet normal. - pos_and_normal = std::make_pair(hit, normal); - return true; - } - return false; -} - // Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. // The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is // aware that the event was reacted to and stops trying to make different sense of it. If the gizmo @@ -509,7 +460,7 @@ void GLGizmoHollow::delete_selected_points() bool GLGizmoHollow::on_mouse(const wxMouseEvent &mouse_event) { - if (!m_input_enabled) return true; + if (!is_input_enabled()) return true; if (mouse_event.Moving()) return false; if (use_grabbers(mouse_event)) return true; @@ -572,13 +523,6 @@ bool GLGizmoHollow::on_mouse(const wxMouseEvent &mouse_event) return false; } -void GLGizmoHollow::process_mesh(SLAPrintObjectStep step, bool postpone_error_messages) -{ - wxGetApp().CallAfter([this, step, postpone_error_messages]() { - wxGetApp().plater()->reslice_SLA_until_step(step, *m_c->selection_info()->model_object(), postpone_error_messages); - }); -} - #if ENABLE_RAYCAST_PICKING void GLGizmoHollow::register_hole_raycasters_for_picking() { @@ -604,22 +548,6 @@ void GLGizmoHollow::unregister_hole_raycasters_for_picking() m_hole_raycasters.clear(); } -void GLGizmoHollow::register_volume_raycasters_for_picking() -{ - for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { - const GLVolume* v = m_volumes.volumes[i]; - m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i, *v->mesh_raycaster, v->world_matrix())); - } -} - -void GLGizmoHollow::unregister_volume_raycasters_for_picking() -{ - for (size_t i = 0; i < m_volume_raycasters.size(); ++i) { - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i); - } - m_volume_raycasters.clear(); -} - void GLGizmoHollow::update_hole_raycasters_for_picking_transform() { const CommonGizmosDataObjects::SelectionInfo* info = m_c->selection_info(); @@ -646,71 +574,6 @@ void GLGizmoHollow::update_hole_raycasters_for_picking_transform() } #endif // ENABLE_RAYCAST_PICKING -static int last_completed_step(const SLAPrint& sla) -{ - int step = -1; - for (int i = 0; i < (int)SLAPrintObjectStep::slaposCount; ++i) { - if (sla.is_step_done((SLAPrintObjectStep)i)) - ++step; - } - return step; -} - -void GLGizmoHollow::update_volumes() -{ - m_volumes.clear(); - unregister_volume_raycasters_for_picking(); - - const ModelObject* mo = m_c->selection_info()->model_object(); - if (mo == nullptr) - return; - - const SLAPrintObject* po = m_c->selection_info()->print_object(); - if (po == nullptr) - return; - - m_input_enabled = false; - - TriangleMesh backend_mesh = po->get_mesh_to_print(); - if (!backend_mesh.empty()) { - // The backend has generated a valid mesh. Use it - backend_mesh.transform(po->trafo().inverse()); - m_volumes.volumes.emplace_back(new GLVolume()); - GLVolume* new_volume = m_volumes.volumes.back(); - new_volume->model.init_from(backend_mesh); - new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation()); - new_volume->set_sla_shift_z(po->get_current_elevation()); - new_volume->mesh_raycaster = std::make_unique(backend_mesh); - m_input_enabled = last_completed_step(*m_c->selection_info()->print_object()->print()) >= slaposAssembly; - if (m_input_enabled) - new_volume->selected = true; // to set the proper color - else - new_volume->set_color(DISABLED_COLOR); - } - - if (m_volumes.volumes.empty()) { - // No valid mesh found in the backend. Use the selection to duplicate the volumes - const Selection& selection = m_parent.get_selection(); - const Selection::IndicesList& idxs = selection.get_volume_idxs(); - for (unsigned int idx : idxs) { - const GLVolume* v = selection.get_volume(idx); - if (!v->is_modifier) { - m_volumes.volumes.emplace_back(new GLVolume()); - GLVolume* new_volume = m_volumes.volumes.back(); - const TriangleMesh& mesh = mo->volumes[v->volume_idx()]->mesh(); - new_volume->model.init_from(mesh); - new_volume->set_instance_transformation(v->get_instance_transformation()); - new_volume->set_volume_transformation(v->get_volume_transformation()); - new_volume->set_sla_shift_z(v->get_sla_shift_z()); - new_volume->set_color(DISABLED_COLOR); - new_volume->mesh_raycaster = std::make_unique(mesh); - } - } - } - - register_volume_raycasters_for_picking(); -} - std::vector> GLGizmoHollow::get_config_options(const std::vector& keys) const { @@ -802,10 +665,10 @@ RENDER_AGAIN: float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left}); window_width = std::max(window_width, button_preview_width); - m_imgui->disabled_begin(!m_input_enabled); + m_imgui->disabled_begin(!is_input_enabled()); if (m_imgui->button(m_desc["preview"])) - process_mesh(slaposDrillHoles); + reslice_until_step(slaposDrillHoles); bool config_changed = false; @@ -823,7 +686,7 @@ RENDER_AGAIN: m_imgui->disabled_end(); - m_imgui->disabled_begin(!m_input_enabled || !m_enable_hollowing); + m_imgui->disabled_begin(!is_input_enabled() || !m_enable_hollowing); ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("offset")); @@ -891,7 +754,7 @@ RENDER_AGAIN: m_new_hole_radius = diameter_upper_cap / 2.f; ImGui::AlignTextToFramePadding(); - m_imgui->disabled_begin(!m_input_enabled); + m_imgui->disabled_begin(!is_input_enabled()); m_imgui->text(m_desc.at("hole_diameter")); ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x); @@ -958,17 +821,17 @@ RENDER_AGAIN: } } - m_imgui->disabled_begin(!m_input_enabled || m_selection_empty); + m_imgui->disabled_begin(!is_input_enabled() || m_selection_empty); remove_selected = m_imgui->button(m_desc.at("remove_selected")); m_imgui->disabled_end(); - m_imgui->disabled_begin(!m_input_enabled || mo->sla_drain_holes.empty()); + m_imgui->disabled_begin(!is_input_enabled() || mo->sla_drain_holes.empty()); remove_all = m_imgui->button(m_desc.at("remove_all")); m_imgui->disabled_end(); // Following is rendered in both editing and non-editing mode: ImGui::Separator(); - m_imgui->disabled_begin(!m_input_enabled); + m_imgui->disabled_begin(!is_input_enabled()); if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); @@ -1043,17 +906,6 @@ std::string GLGizmoHollow::on_get_name() const return _u8L("Hollow and drill"); } - -CommonGizmosDataID GLGizmoHollow::on_get_requirements() const -{ - return CommonGizmosDataID( - int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::InstancesHider) - | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::ObjectClipper)); -} - - void GLGizmoHollow::on_set_state() { if (m_state == m_old_state) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 96f8c6570..c1664b458 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -1,9 +1,8 @@ #ifndef slic3r_GLGizmoHollow_hpp_ #define slic3r_GLGizmoHollow_hpp_ -#include "GLGizmoBase.hpp" +#include "GLGizmoSlaBase.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" -#include "slic3r/GUI/3DScene.hpp" #include #include @@ -21,11 +20,8 @@ namespace GUI { enum class SLAGizmoEventType : unsigned char; class Selection; -class GLGizmoHollow : public GLGizmoBase +class GLGizmoHollow : public GLGizmoSlaBase { -private: - bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); - public: GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); void data_changed() override; @@ -59,30 +55,21 @@ private: #else void render_points(const Selection& selection, bool picking = false); #endif // ENABLE_RAYCAST_PICKING - void render_volumes(); - void process_mesh(SLAPrintObjectStep step, bool postpone_error_messages = false); #if ENABLE_RAYCAST_PICKING void register_hole_raycasters_for_picking(); void unregister_hole_raycasters_for_picking(); - void register_volume_raycasters_for_picking(); - void unregister_volume_raycasters_for_picking(); void update_hole_raycasters_for_picking_transform(); #endif // ENABLE_RAYCAST_PICKING - void update_volumes(); ObjectID m_old_mo_id = -1; #if ENABLE_RAYCAST_PICKING PickingModel m_cylinder; std::vector> m_hole_raycasters; - std::vector> m_volume_raycasters; #else GLModel m_cylinder; #endif // ENABLE_RAYCAST_PICKING - GLVolumeCollection m_volumes; - bool m_input_enabled{ false }; - float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_height = 6.f; mutable std::vector m_selected; // which holes are currently selected @@ -129,7 +116,6 @@ protected: void on_stop_dragging() override; void on_dragging(const UpdateData &data) override; void on_render_input_window(float x, float y, float bottom_limit) override; - virtual CommonGizmosDataID on_get_requirements() const override; std::string on_get_name() const override; bool on_is_activable() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp new file mode 100644 index 000000000..7db24bb11 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp @@ -0,0 +1,171 @@ +#include "libslic3r/libslic3r.h" +#include "GLGizmoSlaBase.hpp" +#include "slic3r/GUI/Camera.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" + +namespace Slic3r { +namespace GUI { + +static const ColorRGBA DISABLED_COLOR = ColorRGBA::DARK_GRAY(); +#if ENABLE_RAYCAST_PICKING +static const int VOLUME_RAYCASTERS_BASE_ID = (int)SceneRaycaster::EIdBase::Gizmo; +#endif // ENABLE_RAYCAST_PICKING + +GLGizmoSlaBase::GLGizmoSlaBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, SLAPrintObjectStep min_step) +: GLGizmoBase(parent, icon_filename, sprite_id) +, m_min_sla_print_object_step((int)min_step) +{} + +void GLGizmoSlaBase::reslice_until_step(SLAPrintObjectStep step, bool postpone_error_messages) +{ + wxGetApp().CallAfter([this, step, postpone_error_messages]() { + wxGetApp().plater()->reslice_SLA_until_step(step, *m_c->selection_info()->model_object(), postpone_error_messages); + }); +} + +CommonGizmosDataID GLGizmoSlaBase::on_get_requirements() const +{ + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::InstancesHider) + | int(CommonGizmosDataID::Raycaster) + | int(CommonGizmosDataID::ObjectClipper)); +} + +void GLGizmoSlaBase::update_volumes() +{ + m_volumes.clear(); + unregister_volume_raycasters_for_picking(); + + const ModelObject* mo = m_c->selection_info()->model_object(); + if (mo == nullptr) + return; + + const SLAPrintObject* po = m_c->selection_info()->print_object(); + if (po == nullptr) + return; + + m_input_enabled = false; + + TriangleMesh backend_mesh = po->get_mesh_to_print(); + if (!backend_mesh.empty()) { + // The backend has generated a valid mesh. Use it + backend_mesh.transform(po->trafo().inverse()); + m_volumes.volumes.emplace_back(new GLVolume()); + GLVolume* new_volume = m_volumes.volumes.back(); + new_volume->model.init_from(backend_mesh); + new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation()); + new_volume->set_sla_shift_z(po->get_current_elevation()); + new_volume->mesh_raycaster = std::make_unique(backend_mesh); + m_input_enabled = last_completed_step(*m_c->selection_info()->print_object()->print()) >= m_min_sla_print_object_step; + if (m_input_enabled) + new_volume->selected = true; // to set the proper color + else + new_volume->set_color(DISABLED_COLOR); + } + + if (m_volumes.volumes.empty()) { + // No valid mesh found in the backend. Use the selection to duplicate the volumes + const Selection& selection = m_parent.get_selection(); + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + for (unsigned int idx : idxs) { + const GLVolume* v = selection.get_volume(idx); + if (!v->is_modifier) { + m_volumes.volumes.emplace_back(new GLVolume()); + GLVolume* new_volume = m_volumes.volumes.back(); + const TriangleMesh& mesh = mo->volumes[v->volume_idx()]->mesh(); + new_volume->model.init_from(mesh); + new_volume->set_instance_transformation(v->get_instance_transformation()); + new_volume->set_volume_transformation(v->get_volume_transformation()); + new_volume->set_sla_shift_z(v->get_sla_shift_z()); + new_volume->set_color(DISABLED_COLOR); + new_volume->mesh_raycaster = std::make_unique(mesh); + } + } + } + +#if ENABLE_RAYCAST_PICKING + register_volume_raycasters_for_picking(); +#endif // ENABLE_RAYCAST_PICKING +} + +void GLGizmoSlaBase::render_volumes() +{ + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_clip"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("emission_factor", 0.0f); + const Camera& camera = wxGetApp().plater()->get_camera(); + + ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane(); + clipping_plane.set_normal(-clipping_plane.get_normal()); + m_volumes.set_clipping_plane(clipping_plane.get_data()); + + m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix()); + shader->stop_using(); + +} + +#if ENABLE_RAYCAST_PICKING +void GLGizmoSlaBase::register_volume_raycasters_for_picking() +{ + for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { + const GLVolume* v = m_volumes.volumes[i]; + m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix())); + } +} + +void GLGizmoSlaBase::unregister_volume_raycasters_for_picking() +{ + for (size_t i = 0; i < m_volume_raycasters.size(); ++i) { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i); + } + m_volume_raycasters.clear(); +} +#endif // ENABLE_RAYCAST_PICKING + +int GLGizmoSlaBase::last_completed_step(const SLAPrint& sla) +{ + int step = -1; + for (int i = 0; i < (int)SLAPrintObjectStep::slaposCount; ++i) { + if (sla.is_step_done((SLAPrintObjectStep)i)) + ++step; + } + return step; +} + +// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal +// Return false if no intersection was found, true otherwise. +bool GLGizmoSlaBase::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) +{ + if (m_c->raycaster()->raycasters().size() != 1) + return false; + if (!m_c->raycaster()->raycaster()) + return false; + if (m_volumes.volumes.empty()) + return false; + + // The raycaster query + Vec3f hit; + Vec3f normal; + if (m_c->raycaster()->raycaster()->unproject_on_mesh( + mouse_pos, + m_volumes.volumes.front()->world_matrix(), + wxGetApp().plater()->get_camera(), + hit, + normal, + m_c->object_clipper()->get_position() != 0.0 ? m_c->object_clipper()->get_clipping_plane() : nullptr)) { + // Return both the point and the facet normal. + pos_and_normal = std::make_pair(hit, normal); + return true; + } + return false; +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp new file mode 100644 index 000000000..ca87d75ac --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp @@ -0,0 +1,59 @@ +#ifndef slic3r_GLGizmoSlaBase_hpp_ +#define slic3r_GLGizmoSlaBase_hpp_ + +#include "GLGizmoBase.hpp" +#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/SceneRaycaster.hpp" +#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/Point.hpp" + +#include +#include +#include + +namespace Slic3r { + +class SLAPrint; + +namespace GUI { + +class GLCanvas3D; + +class GLGizmoSlaBase : public GLGizmoBase +{ +public: + GLGizmoSlaBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, SLAPrintObjectStep min_step); + + void reslice_until_step(SLAPrintObjectStep step, bool postpone_error_messages = false); + +protected: + virtual CommonGizmosDataID on_get_requirements() const override; + + void update_volumes(); + void render_volumes(); + +#if ENABLE_RAYCAST_PICKING + void register_volume_raycasters_for_picking(); + void unregister_volume_raycasters_for_picking(); +#endif // ENABLE_RAYCAST_PICKING + + bool is_input_enabled() const { return m_input_enabled; } + int get_min_sla_print_object_step() const { return m_min_sla_print_object_step; } + + static int last_completed_step(const SLAPrint& sla); + + bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); + +private: + GLVolumeCollection m_volumes; + bool m_input_enabled{ false }; + int m_min_sla_print_object_step{ -1 }; +#if ENABLE_RAYCAST_PICKING + std::vector> m_volume_raycasters; +#endif // ENABLE_RAYCAST_PICKING +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLGizmoSlaBase_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 291a8323a..2884d4969 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -1,8 +1,6 @@ +#include "libslic3r/libslic3r.h" // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoSlaSupports.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/Camera.hpp" -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "slic3r/GUI/MainFrame.hpp" #include "slic3r/Utils/UndoRedo.hpp" @@ -12,11 +10,9 @@ #include #include -#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI_ObjectSettings.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/NotificationManager.hpp" #include "slic3r/GUI/MsgDialog.hpp" #include "libslic3r/PresetBundle.hpp" @@ -30,10 +26,8 @@ static const double CONE_HEIGHT = 0.75; namespace Slic3r { namespace GUI { -static const ColorRGBA DISABLED_COLOR = ColorRGBA::DARK_GRAY(); - GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) + : GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles) {} bool GLGizmoSlaSupports::on_init() @@ -62,16 +56,6 @@ bool GLGizmoSlaSupports::on_init() return true; } -static int last_completed_step(const SLAPrint& sla) -{ - int step = -1; - for (int i = 0; i < (int)SLAPrintObjectStep::slaposCount; ++i) { - if (sla.is_step_done((SLAPrintObjectStep)i)) - ++step; - } - return step; -} - void GLGizmoSlaSupports::data_changed() { if (! m_c->selection_info()) @@ -89,8 +73,9 @@ void GLGizmoSlaSupports::data_changed() if (mo) { m_c->instances_hider()->set_hide_full_scene(true); const SLAPrintObject* po = m_c->selection_info()->print_object(); - if (po != nullptr && last_completed_step(*po->print()) < (int)slaposDrillHoles) - process_mesh(slaposDrillHoles, false); + const int required_step = get_min_sla_print_object_step(); + if (po != nullptr && last_completed_step(*po->print()) < required_step) + reslice_until_step((SLAPrintObjectStep)required_step, false); update_volumes(); @@ -380,24 +365,6 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) #endif // !ENABLE_LEGACY_OPENGL_REMOVAL } -void GLGizmoSlaSupports::render_volumes() -{ - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_clip"); - if (shader == nullptr) - return; - - shader->start_using(); - shader->set_uniform("emission_factor", 0.0f); - const Camera& camera = wxGetApp().plater()->get_camera(); - - ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane(); - clipping_plane.set_normal(-clipping_plane.get_normal()); - m_volumes.set_clipping_plane(clipping_plane.get_data()); - - m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix()); - shader->stop_using(); -} - bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const { if (m_c->object_clipper()->get_position() == 0.) @@ -413,33 +380,6 @@ bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); } - - -// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal -// Return false if no intersection was found, true otherwise. -bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) -{ - if (!m_c->raycaster()->raycaster()) - return false; - - // The raycaster query - Vec3f hit; - Vec3f normal; - if (m_c->raycaster()->raycaster()->unproject_on_mesh( - mouse_pos, - m_volumes.volumes.front()->world_matrix(), - wxGetApp().plater()->get_camera(), - hit, - normal, - m_c->object_clipper()->get_position() != 0.0 ? m_c->object_clipper()->get_clipping_plane() : nullptr)) { - // Return both the point and the facet normal. - pos_and_normal = std::make_pair(hit, normal); - return true; - } - - return false; -} - // Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. // The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is // aware that the event was reacted to and stops trying to make different sense of it. If the gizmo @@ -842,7 +782,7 @@ RENDER_AGAIN: } } else { // not in editing mode: - m_imgui->disabled_begin(!m_input_enabled); + m_imgui->disabled_begin(!is_input_enabled()); ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("minimal_distance")); @@ -895,7 +835,7 @@ RENDER_AGAIN: m_imgui->disabled_end(); - m_imgui->disabled_begin(!m_input_enabled || m_normal_cache.empty()); + m_imgui->disabled_begin(!is_input_enabled() || m_normal_cache.empty()); remove_all = m_imgui->button(m_desc.at("remove_all")); m_imgui->disabled_end(); @@ -908,7 +848,7 @@ RENDER_AGAIN: // Following is rendered in both editing and non-editing mode: - m_imgui->disabled_begin(!m_input_enabled); + m_imgui->disabled_begin(!is_input_enabled()); ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); @@ -991,17 +931,6 @@ std::string GLGizmoSlaSupports::on_get_name() const return _u8L("SLA Support Points"); } -CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const -{ - return CommonGizmosDataID( - int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::InstancesHider) - | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::ObjectClipper)); -} - - - void GLGizmoSlaSupports::ask_about_changes_call_after(std::function on_yes, std::function on_no) { wxGetApp().CallAfter([on_yes, on_no]() { @@ -1189,7 +1118,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() mo->sla_support_points.clear(); mo->sla_support_points = m_normal_cache; - reslice_SLA_supports(); + reslice_until_step(slaposPad); } } @@ -1221,17 +1150,9 @@ bool GLGizmoSlaSupports::has_backend_supports() const return false; } -void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) const -{ - wxGetApp().CallAfter([this, postpone_error_messages]() { - wxGetApp().plater()->reslice_SLA_supports( - *m_c->selection_info()->model_object(), postpone_error_messages); - }); -} - bool GLGizmoSlaSupports::on_mouse(const wxMouseEvent &mouse_event) { - if (!m_input_enabled) return true; + if (!is_input_enabled()) return true; if (mouse_event.Moving()) return false; if (!mouse_event.ShiftDown() && !mouse_event.AltDown() && use_grabbers(mouse_event)) return true; @@ -1324,7 +1245,7 @@ void GLGizmoSlaSupports::auto_generate() if (mo->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points")); - wxGetApp().CallAfter([this]() { reslice_SLA_supports(); }); + wxGetApp().CallAfter([this]() { reslice_until_step(slaposPad); }); mo->sla_points_status = sla::PointsStatus::Generating; } } @@ -1395,22 +1316,6 @@ void GLGizmoSlaSupports::unregister_point_raycasters_for_picking() m_point_raycasters.clear(); } -void GLGizmoSlaSupports::register_volume_raycasters_for_picking() -{ - for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { - const GLVolume* v = m_volumes.volumes[i]; - m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i, *v->mesh_raycaster, v->world_matrix())); - } -} - -void GLGizmoSlaSupports::unregister_volume_raycasters_for_picking() -{ - for (size_t i = 0; i < m_volume_raycasters.size(); ++i) { - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i); - } - m_volume_raycasters.clear(); -} - void GLGizmoSlaSupports::update_point_raycasters_for_picking_transform() { if (m_editing_cache.empty()) @@ -1442,68 +1347,6 @@ void GLGizmoSlaSupports::update_point_raycasters_for_picking_transform() } #endif // ENABLE_RAYCAST_PICKING -void GLGizmoSlaSupports::update_volumes() -{ - m_volumes.clear(); - unregister_volume_raycasters_for_picking(); - - const ModelObject* mo = m_c->selection_info()->model_object(); - if (mo == nullptr) - return; - - const SLAPrintObject* po = m_c->selection_info()->print_object(); - if (po == nullptr) - return; - - m_input_enabled = false; - - TriangleMesh backend_mesh = po->get_mesh_to_print(); - if (!backend_mesh.empty()) { - // The backend has generated a valid mesh. Use it - backend_mesh.transform(po->trafo().inverse()); - m_volumes.volumes.emplace_back(new GLVolume()); - GLVolume* new_volume = m_volumes.volumes.back(); - new_volume->model.init_from(backend_mesh); - new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation()); - new_volume->set_sla_shift_z(po->get_current_elevation()); - new_volume->mesh_raycaster = std::make_unique(backend_mesh); - m_input_enabled = last_completed_step(*m_c->selection_info()->print_object()->print()) >= slaposDrillHoles; - if (m_input_enabled) - new_volume->selected = true; // to set the proper color - else - new_volume->set_color(DISABLED_COLOR); - } - - if (m_volumes.volumes.empty()) { - // No valid mesh found in the backend. Use the selection to duplicate the volumes - const Selection& selection = m_parent.get_selection(); - const Selection::IndicesList& idxs = selection.get_volume_idxs(); - for (unsigned int idx : idxs) { - const GLVolume* v = selection.get_volume(idx); - if (!v->is_modifier) { - m_volumes.volumes.emplace_back(new GLVolume()); - GLVolume* new_volume = m_volumes.volumes.back(); - const TriangleMesh& mesh = mo->volumes[v->volume_idx()]->mesh(); - new_volume->model.init_from(mesh); - new_volume->set_instance_transformation(v->get_instance_transformation()); - new_volume->set_volume_transformation(v->get_volume_transformation()); - new_volume->set_sla_shift_z(v->get_sla_shift_z()); - new_volume->set_color(DISABLED_COLOR); - new_volume->mesh_raycaster = std::make_unique(mesh); - } - } - } - - register_volume_raycasters_for_picking(); -} - -void GLGizmoSlaSupports::process_mesh(SLAPrintObjectStep step, bool postpone_error_messages) -{ - wxGetApp().CallAfter([this, step, postpone_error_messages]() { - wxGetApp().plater()->reslice_SLA_until_step(step, *m_c->selection_info()->model_object(), postpone_error_messages); - }); -} - SlaGizmoHelpDialog::SlaGizmoHelpDialog() : wxDialog(nullptr, wxID_ANY, _L("SLA gizmo keyboard shortcuts"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index bc5eede66..c10d225da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -1,9 +1,8 @@ #ifndef slic3r_GLGizmoSlaSupports_hpp_ #define slic3r_GLGizmoSlaSupports_hpp_ -#include "GLGizmoBase.hpp" +#include "GLGizmoSlaBase.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" -#include "slic3r/GUI/3DScene.hpp" #include "libslic3r/SLA/SupportPoint.hpp" #include "libslic3r/ObjectID.hpp" @@ -20,11 +19,9 @@ namespace GUI { class Selection; enum class SLAGizmoEventType : unsigned char; -class GLGizmoSlaSupports : public GLGizmoBase +class GLGizmoSlaSupports : public GLGizmoSlaBase { private: - bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); - static constexpr float RenderPointScale = 1.f; class CacheEntry { @@ -65,7 +62,6 @@ public: bool is_in_editing_mode() const override { return m_editing_mode; } bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); } bool has_backend_supports() const; - void reslice_SLA_supports(bool postpone_error_messages = false) const; bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Entering SLA support points"); } @@ -93,17 +89,12 @@ private: #else void render_points(const Selection& selection, bool picking = false); #endif // ENABLE_RAYCAST_PICKING - void render_volumes(); bool unsaved_changes() const; #if ENABLE_RAYCAST_PICKING void register_point_raycasters_for_picking(); void unregister_point_raycasters_for_picking(); - void register_volume_raycasters_for_picking(); - void unregister_volume_raycasters_for_picking(); void update_point_raycasters_for_picking_transform(); #endif // ENABLE_RAYCAST_PICKING - void update_volumes(); - void process_mesh(SLAPrintObjectStep step, bool postpone_error_messages = false); bool m_lock_unique_islands = false; bool m_editing_mode = false; // Is editing mode active? @@ -120,15 +111,11 @@ private: PickingModel m_sphere; PickingModel m_cone; std::vector, std::shared_ptr>> m_point_raycasters; - std::vector> m_volume_raycasters; #else GLModel m_cone; GLModel m_sphere; #endif // ENABLE_RAYCAST_PICKING - GLVolumeCollection m_volumes; - bool m_input_enabled{ false }; - // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; @@ -174,7 +161,6 @@ protected: std::string on_get_name() const override; bool on_is_activable() const override; bool on_is_selectable() const override; - virtual CommonGizmosDataID on_get_requirements() const override; void on_load(cereal::BinaryInputArchive& ar) override; void on_save(cereal::BinaryOutputArchive& ar) const override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 37d1d3de4..ad0e268f6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -683,7 +683,7 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot) m_serializing = false; if (m_current == SlaSupports && snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS) - dynamic_cast(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true); + dynamic_cast(m_gizmos[SlaSupports].get())->reslice_until_step(slaposPad, true); } #if ENABLE_LEGACY_OPENGL_REMOVAL diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d57963e25..9db47ffb0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6370,16 +6370,6 @@ void Plater::reslice() p->preview->reload_print(!clean_gcode_toolpaths); } -void Plater::reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages) -{ - reslice_SLA_until_step(slaposPad, object, postpone_error_messages); -} - -void Plater::reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages) -{ - reslice_SLA_until_step(slaposDrillHoles, object, postpone_error_messages); -} - void Plater::reslice_until_step_inner(int step, const ModelObject &object, bool postpone_error_messages) { //FIXME Don't reslice if export of G-code or sending to OctoPrint is running. diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 77a401f3f..5818ecf56 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -266,8 +266,6 @@ public: void export_toolpaths_to_obj() const; void reslice(); void reslice_FFF_until_step(PrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false); - void reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages = false); - void reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages = false); void reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false); void clear_before_change_mesh(int obj_idx);