Added new base class for SLA gizmos to remove duplicated code

This commit is contained in:
enricoturri1966 2022-11-04 12:44:54 +01:00 committed by tamasmeszaros
parent c28a00ae04
commit 602c48a116
10 changed files with 259 additions and 372 deletions

View File

@ -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

View File

@ -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 <GL/glew.h>
@ -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<Vec3f, Vec3f>& 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<GUI::MeshRaycaster>(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<GUI::MeshRaycaster>(mesh);
}
}
}
register_volume_raycasters_for_picking();
}
std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>>
GLGizmoHollow::get_config_options(const std::vector<std::string>& 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)

View File

@ -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 <libslic3r/SLA/Hollowing.hpp>
#include <libslic3r/ObjectID.hpp>
@ -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<Vec3f, Vec3f>& 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<std::shared_ptr<SceneRaycasterItem>> m_hole_raycasters;
std::vector<std::shared_ptr<SceneRaycasterItem>> 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<bool> 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;

View File

@ -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<GUI::MeshRaycaster>(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<GUI::MeshRaycaster>(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<Vec3f, Vec3f>& 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

View File

@ -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 <vector>
#include <string>
#include <memory>
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<Vec3f, Vec3f>& 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<std::shared_ptr<SceneRaycasterItem>> m_volume_raycasters;
#endif // ENABLE_RAYCAST_PICKING
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GLGizmoSlaBase_hpp_

View File

@ -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 <wx/settings.h>
#include <wx/stattext.h>
#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<Vec3f, Vec3f>& 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<void()> on_yes, std::function<void()> 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<GUI::MeshRaycaster>(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<GUI::MeshRaycaster>(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)
{

View File

@ -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<Vec3f, Vec3f>& 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::pair<std::shared_ptr<SceneRaycasterItem>, std::shared_ptr<SceneRaycasterItem>>> m_point_raycasters;
std::vector<std::shared_ptr<SceneRaycasterItem>> 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<std::string, wxString> 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;
};

View File

@ -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<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true);
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->reslice_until_step(slaposPad, true);
}
#if ENABLE_LEGACY_OPENGL_REMOVAL

View File

@ -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.

View File

@ -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);