Merge branch 'lm_sla_supports_auto2'

This commit is contained in:
bubnikv 2019-02-20 10:58:34 +01:00
commit 464808ac49
32 changed files with 1644 additions and 791 deletions

View file

@ -793,7 +793,7 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool
glsafe(::glDisable(GL_BLEND));
}
void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface) const
void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func) const
{
glsafe(glEnable(GL_BLEND));
glsafe(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
@ -805,7 +805,7 @@ void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface)
glsafe(glEnableClientState(GL_VERTEX_ARRAY));
glsafe(glEnableClientState(GL_NORMAL_ARRAY));
GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, std::function<bool(const GLVolume&)>());
GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, filter_func);
for (GLVolumeWithZ& volume : to_render)
{
volume.first->set_render_color();

View file

@ -456,7 +456,7 @@ public:
// Render the volumes by OpenGL.
void render_VBOs(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
void render_legacy(ERenderType type, bool disable_cullface) const;
void render_legacy(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
// Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects

View file

@ -3158,6 +3158,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec
float cnv_h = (float)canvas.get_canvas_size().get_height();
float height = _get_total_overlay_height();
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
@ -3440,42 +3441,28 @@ void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object)
reinterpret_cast<GLGizmoFlatten*>(it->second)->set_flattening_data(model_object);
}
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLCanvas3D::Gizmos::set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection)
#else
void GLCanvas3D::Gizmos::set_model_object_ptr(ModelObject* model_object)
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
{
if (!m_enabled)
return;
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, selection);
#else
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_model_object_ptr(model_object);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
void GLCanvas3D::Gizmos::clicked_on_object(const Vec2d& mouse_position)
// Returns true if the gizmo used the event to do something, false otherwise.
bool GLCanvas3D::Gizmos::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down)
{
if (!m_enabled)
return;
return false;
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->clicked_on_object(mouse_position);
}
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->mouse_event(action, mouse_position, shift_down);
void GLCanvas3D::Gizmos::delete_current_grabber(bool delete_all)
{
if (!m_enabled)
return;
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->delete_current_grabber(delete_all);
return false;
}
void GLCanvas3D::Gizmos::render_current_gizmo(const GLCanvas3D::Selection& selection) const
@ -4097,6 +4084,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
, m_moving(false)
, m_color_by("volume")
, m_reload_delayed(false)
, m_render_sla_auxiliaries(true)
#if !ENABLE_IMGUI
, m_external_gizmo_widgets_parent(nullptr)
#endif // not ENABLE_IMGUI
@ -4255,6 +4243,28 @@ int GLCanvas3D::check_volumes_outside_state() const
return (int)state;
}
void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible)
{
for (GLVolume* vol : m_volumes.volumes) {
if (vol->composite_id.volume_id < 0)
vol->is_active = visible;
}
m_render_sla_auxiliaries = visible;
}
void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject* mo, int instance_idx)
{
for (GLVolume* vol : m_volumes.volumes) {
if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo)
&& (instance_idx == -1 || vol->composite_id.instance_id == instance_idx))
vol->is_active = visible;
}
if (visible && !mo)
toggle_sla_auxiliaries_visibility(true);
}
void GLCanvas3D::set_config(const DynamicPrintConfig* config)
{
m_config = config;
@ -4609,9 +4619,9 @@ void GLCanvas3D::render()
// this position is used later into on_mouse() to drag the objects
m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast<int>());
_render_current_gizmo();
_render_selection_sidebar_hints();
_render_current_gizmo();
#if ENABLE_SHOW_CAMERA_TARGET
_render_camera_target();
#endif // ENABLE_SHOW_CAMERA_TARGET
@ -5119,6 +5129,7 @@ void GLCanvas3D::bind_event_handlers()
m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
m_canvas->Bind(wxEVT_KEY_UP, &GLCanvas3D::on_key_up, this);
m_canvas->Bind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this);
m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this);
m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this);
@ -5144,6 +5155,7 @@ void GLCanvas3D::unbind_event_handlers()
m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
m_canvas->Unbind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
m_canvas->Unbind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
m_canvas->Unbind(wxEVT_KEY_UP, &GLCanvas3D::on_key_up, this);
m_canvas->Unbind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this);
m_canvas->Unbind(wxEVT_TIMER, &GLCanvas3D::on_timer, this);
m_canvas->Unbind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this);
@ -5187,7 +5199,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
switch (keyCode) {
case 'a':
case 'A':
case WXK_CONTROL_A: post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); break;
case WXK_CONTROL_A:
if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::SelectAll)) // Sla gizmo selects all support points
m_dirty = true;
else
post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL));
break;
#ifdef __APPLE__
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
#else /* __APPLE__ */
@ -5208,7 +5225,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#else /* __APPLE__ */
case WXK_DELETE:
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE)); break;
if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::Delete))
m_dirty = true;
else
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
break;
case '0': { select_view("iso"); break; }
case '1': { select_view("top"); break; }
case '2': { select_view("bottom"); break; }
@ -5245,6 +5267,16 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
}
}
void GLCanvas3D::on_key_up(wxKeyEvent& evt)
{
// see include/wx/defs.h enum wxKeyCode
int keyCode = evt.GetKeyCode();
// shift has been just released - SLA gizmo might want to close rectangular selection.
if (m_gizmos.get_current_type() == Gizmos::SlaSupports && keyCode == WXK_SHIFT && m_gizmos.mouse_event(SLAGizmoEventType::ShiftUp))
m_dirty = true;
}
void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
{
// Ignore the wheel events if the middle button is pressed.
@ -5392,22 +5424,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
}
#if !ENABLE_IMGUI
else if ((m_gizmos.get_current_type() == Gizmos::SlaSupports) && gizmo_reset_rect_contains(*this, pos(0), pos(1)))
{
if (evt.LeftDown())
{
m_gizmos.delete_current_grabber(true);
m_dirty = true;
}
}
#endif // not ENABLE_IMGUI
else if (!m_selection.is_empty() && gizmos_overlay_contains_mouse)
{
m_gizmos.update_on_off_state(*this, m_mouse.position, m_selection);
_update_gizmos_data();
m_dirty = true;
}
else if (evt.LeftDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown() && m_gizmos.mouse_event(SLAGizmoEventType::LeftDown, Vec2d(pos(0), pos(1)), evt.ShiftDown()))
{
// the gizmo got the event and took some action, there is no need to do anything more
}
else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse())
{
_update_gizmos_data();
@ -5423,9 +5449,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse() && evt.RightDown()) {
if (m_gizmos.get_current_type() == Gizmos::SlaSupports)
m_gizmos.delete_current_grabber();
else if ((selected_object_idx != -1) && evt.RightDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::RightDown))
{
// event was taken care of by the SlaSupports gizmo
}
else if (view_toolbar_contains_mouse != -1)
{
@ -5530,7 +5556,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
}
}
else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown) && (m_mouse.drag.move_volume_idx != -1))
else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown)
&& (m_mouse.drag.move_volume_idx != -1) && m_gizmos.get_current_type() != Gizmos::SlaSupports /* don't allow dragging objects with the Sla gizmo on */)
{
#if ENABLE_MOVE_MIN_THRESHOLD
if (!m_mouse.drag.move_requires_threshold)
@ -5590,6 +5617,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
else if (evt.Dragging() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown() && m_gizmos.mouse_event(SLAGizmoEventType::Dragging, Vec2d(pos(0), pos(1)), evt.ShiftDown()))
{
// the gizmo got the event and took some action, no need to do anything more here
m_dirty = true;
}
else if (evt.Dragging() && !gizmos_overlay_contains_mouse)
{
m_mouse.dragging = true;
@ -5645,6 +5677,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
_stop_timer();
m_layers_editing.accept_changes(*this);
}
else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports && !m_gizmos.is_dragging()
&& !m_mouse.dragging && m_gizmos.mouse_event(SLAGizmoEventType::LeftUp, Vec2d(pos(0), pos(1)), evt.ShiftDown()))
{
// the gizmo got the event and took some action, no need to do anything more
}
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
{
m_regenerate_volumes = false;
@ -5654,16 +5691,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// of the scene with the background processing data should be performed.
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
}
else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_hover_volume_id != -1)
else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging()
&& !is_layers_editing_enabled() && (m_gizmos.get_current_type() != Gizmos::SlaSupports || !m_gizmos.mouse_event(SLAGizmoEventType::LeftUp, Vec2d(pos(0), pos(1)), evt.ShiftDown())))
{
int id = m_selection.get_object_idx();
// SLA gizmo cannot be deselected by clicking in canvas area to avoid inadvertent unselection and losing manual changes
// that's why the mouse_event function was called so that the gizmo can refuse the deselection in manual editing mode
if ((id != -1) && (m_model != nullptr)) {
m_gizmos.clicked_on_object(Vec2d(pos(0), pos(1)));
}
}
else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled())
{
// deselect and propagate event through callback
if (!evt.ShiftDown() && m_picking_enabled && !m_toolbar_action_running && !m_mouse.ignore_up_event)
{
@ -5696,10 +5729,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
do_rotate();
break;
}
case Gizmos::SlaSupports:
// End of mouse dragging, update the SLAPrint/SLAPrintObjects with the new support points.
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
break;
default:
break;
}
@ -6584,7 +6613,9 @@ void GLCanvas3D::_render_objects() const
m_layers_editing.render_volumes(*this, this->m_volumes);
} else {
// do not cull backfaces to show broken geometry, if any
m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled);
m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled, [this](const GLVolume& volume) {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
});
}
m_volumes.render_VBOs(GLVolumeCollection::Transparent, false);
m_shader.stop_using();
@ -6600,7 +6631,9 @@ void GLCanvas3D::_render_objects() const
}
// do not cull backfaces to show broken geometry, if any
m_volumes.render_legacy(GLVolumeCollection::Opaque, m_picking_enabled);
m_volumes.render_legacy(GLVolumeCollection::Opaque, m_picking_enabled, [this](const GLVolume& volume) {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
});
m_volumes.render_legacy(GLVolumeCollection::Transparent, false);
if (m_use_clipping_planes)
@ -6681,7 +6714,7 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const
::glColor4fv(vol->render_color);
}
if (!fake_colors || !vol->disabled)
if ((!fake_colors || !vol->disabled) && (vol->composite_id.volume_id >= 0 || m_render_sla_auxiliaries))
vol->render();
++volume_id;
@ -6832,20 +6865,20 @@ void GLCanvas3D::_render_sla_slices() const
{
// calculate model bottom cap
if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size()))
bottom_obj_triangles = triangulate_expolygons_3df(model_slices[it_min_z->second.model_slices_idx], min_z, true);
bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true);
// calculate support bottom cap
if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
bottom_sup_triangles = triangulate_expolygons_3df(support_slices[it_min_z->second.support_slices_idx], min_z, true);
bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true);
}
if (it_max_z != index.end())
{
// calculate model top cap
if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size()))
top_obj_triangles = triangulate_expolygons_3df(model_slices[it_max_z->second.model_slices_idx], max_z, false);
top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false);
// calculate support top cap
if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
top_sup_triangles = triangulate_expolygons_3df(support_slices[it_max_z->second.support_slices_idx], max_z, false);
top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false);
}
}
@ -6958,11 +6991,7 @@ void GLCanvas3D::_update_gizmos_data()
m_gizmos.set_rotation(Vec3d::Zero());
ModelObject* model_object = m_model->objects[m_selection.get_object_idx()];
m_gizmos.set_flattening_data(model_object);
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_gizmos.set_sla_support_data(model_object, m_selection);
#else
m_gizmos.set_model_object_ptr(model_object);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
else if (m_selection.is_single_volume() || m_selection.is_single_modifier())
{
@ -6970,22 +6999,14 @@ void GLCanvas3D::_update_gizmos_data()
m_gizmos.set_scale(volume->get_volume_scaling_factor());
m_gizmos.set_rotation(Vec3d::Zero());
m_gizmos.set_flattening_data(nullptr);
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_gizmos.set_sla_support_data(nullptr, m_selection);
#else
m_gizmos.set_model_object_ptr(nullptr);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
else
{
m_gizmos.set_scale(Vec3d::Ones());
m_gizmos.set_rotation(Vec3d::Zero());
m_gizmos.set_flattening_data(m_selection.is_from_single_object() ? m_model->objects[m_selection.get_object_idx()] : nullptr);
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_gizmos.set_sla_support_data(nullptr, m_selection);
#else
m_gizmos.set_model_object_ptr(nullptr);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
}

View file

@ -132,6 +132,18 @@ wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
// this describes events being passed from GLCanvas3D to SlaSupport gizmo
enum class SLAGizmoEventType {
LeftDown = 1,
LeftUp,
RightDown,
Dragging,
Delete,
SelectAll,
ShiftUp
};
class GLCanvas3D
{
struct GCodePreviewVolumeIndex
@ -788,12 +800,8 @@ private:
void set_flattening_data(const ModelObject* model_object);
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection);
#else
void set_model_object_ptr(ModelObject* model_object);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
void clicked_on_object(const Vec2d& mouse_position);
bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false);
void delete_current_grabber(bool delete_all = false);
void render_current_gizmo(const Selection& selection) const;
@ -923,6 +931,7 @@ private:
bool m_multisample_allowed;
bool m_regenerate_volumes;
bool m_moving;
bool m_render_sla_auxiliaries;
std::string m_color_by;
@ -954,6 +963,9 @@ public:
void reset_volumes();
int check_volumes_outside_state() const;
void toggle_sla_auxiliaries_visibility(bool visible);
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void set_config(const DynamicPrintConfig* config);
void set_process(BackgroundSlicingProcess* process);
void set_model(Model* model);
@ -1050,6 +1062,7 @@ public:
void on_size(wxSizeEvent& evt);
void on_idle(wxIdleEvent& evt);
void on_char(wxKeyEvent& evt);
void on_key_up(wxKeyEvent& evt);
void on_mouse_wheel(wxMouseEvent& evt);
void on_timer(wxTimerEvent& evt);
void on_mouse(wxMouseEvent& evt);

View file

@ -7,7 +7,7 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/SLA/SLASupportTree.hpp"
#include "libslic3r/SLA/SLACommon.hpp"
#include "libslic3r/SLAPrint.hpp"
#include <cstdio>
@ -1741,28 +1741,20 @@ Vec3d GLGizmoFlatten::get_flattening_normal() const
}
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent)
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
: GLGizmoBase(parent), m_starting_center(Vec3d::Zero()), m_quadric(nullptr)
#else
: GLGizmoBase(parent), m_starting_center(Vec3d::Zero())
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
{
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
// contains mirroring (normals are reverted)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
GLGizmoSlaSupports::~GLGizmoSlaSupports()
{
if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric);
}
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
bool GLGizmoSlaSupports::on_init()
{
@ -1782,7 +1774,6 @@ bool GLGizmoSlaSupports::on_init()
return true;
}
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection)
{
m_starting_center = Vec3d::Zero();
@ -1791,208 +1782,162 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G
if (selection.is_empty())
m_old_instance_id = -1;
if ((model_object != nullptr) && selection.is_from_single_instance())
m_active_instance = selection.get_instance_idx();
if (model_object && selection.is_from_single_instance())
{
if (is_mesh_update_necessary())
update_mesh();
// If there are no points, let's ask the backend if it calculated some.
if (model_object->sla_support_points.empty() && m_parent.sla_print()->is_step_done(slaposSupportPoints)) {
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
if (po->model_object()->id() == model_object->id()) {
const Eigen::MatrixXd& points = po->get_support_points();
for (unsigned int i=0; i<points.rows();++i)
model_object->sla_support_points.push_back(Vec3f(po->trafo().inverse().cast<float>() * Vec3f(points(i,0), points(i,1), points(i,2))));
break;
}
}
if (m_editing_mode_cache.empty() && m_parent.sla_print()->is_step_done(slaposSupportPoints))
get_data_from_backend();
if (m_model_object != m_old_model_object)
m_editing_mode = false;
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
}
}
}
#else
void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object)
{
if (model_object != nullptr) {
m_starting_center = Vec3d::Zero();
m_model_object = model_object;
int selected_instance = m_parent.get_selection().get_instance_idx();
assert(selected_instance < (int)model_object->instances.size());
m_instance_matrix = model_object->instances[selected_instance]->get_matrix();
if (is_mesh_update_necessary())
update_mesh();
}
}
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const
{
::glEnable(GL_BLEND);
::glEnable(GL_DEPTH_TEST);
#if !ENABLE_SLA_SUPPORT_GIZMO_MOD
// the dragged_offset is a vector measuring where was the object moved
// with the gizmo being on. This is reset in set_model_object_ptr and
// does not work correctly when there are multiple copies.
if (m_starting_center == Vec3d::Zero())
m_starting_center = selection.get_bounding_box().center();
Vec3d dragged_offset = selection.get_bounding_box().center() - m_starting_center;
#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD
for (auto& g : m_grabbers) {
g.color[0] = 1.f;
g.color[1] = 0.f;
g.color[2] = 0.f;
}
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
render_grabbers(selection, false);
#else
//::glTranslatef((GLfloat)dragged_offset(0), (GLfloat)dragged_offset(1), (GLfloat)dragged_offset(2));
render_grabbers(false);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
render_points(selection, false);
render_selection_rectangle();
#if !ENABLE_IMGUI
render_tooltip_texture();
#endif // not ENABLE_IMGUI
::glDisable(GL_BLEND);
}
void GLGizmoSlaSupports::render_selection_rectangle() const
{
if (!m_selection_rectangle_active)
return;
::glLineWidth(1.5f);
float render_color[3] = {1.f, 0.f, 0.f};
::glColor3fv(render_color);
::glPushAttrib(GL_TRANSFORM_BIT); // remember current MatrixMode
::glMatrixMode(GL_MODELVIEW); // cache modelview matrix and set to identity
::glPushMatrix();
::glLoadIdentity();
::glMatrixMode(GL_PROJECTION); // cache projection matrix and set to identity
::glPushMatrix();
::glLoadIdentity();
::glOrtho(0.f, m_canvas_width, m_canvas_height, 0.f, -1.f, 1.f); // set projection matrix so that world coords = window coords
// render the selection rectangle (window coordinates):
::glPushAttrib(GL_ENABLE_BIT);
::glLineStipple(4, 0xAAAA);
::glEnable(GL_LINE_STIPPLE);
::glBegin(GL_LINE_LOOP);
::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f);
::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f);
::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f);
::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f);
::glEnd();
::glPopAttrib();
::glPopMatrix(); // restore former projection matrix
::glMatrixMode(GL_MODELVIEW);
::glPopMatrix(); // restore former modelview matrix
::glPopAttrib(); // restore former MatrixMode
}
void GLGizmoSlaSupports::on_render_for_picking(const GLCanvas3D::Selection& selection) const
{
::glEnable(GL_DEPTH_TEST);
for (unsigned int i=0; i<m_grabbers.size(); ++i) {
m_grabbers[i].color[0] = 1.0f;
m_grabbers[i].color[1] = 1.0f;
m_grabbers[i].color[2] = picking_color_component(i);
}
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
render_grabbers(selection, true);
#else
render_grabbers(true);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
render_points(selection, true);
}
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLGizmoSlaSupports::render_grabbers(const GLCanvas3D::Selection& selection, bool picking) const
void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, bool picking) const
{
if (m_quadric == nullptr)
if (m_quadric == nullptr || !selection.is_from_single_instance())
return;
if (!selection.is_from_single_instance())
return;
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
double z_shift = v->get_sla_shift_z();
::glPushMatrix();
::glTranslated(0.0, 0.0, z_shift);
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
::glMultMatrixd(m.data());
if (!picking)
::glEnable(GL_LIGHTING);
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
double z_shift = vol->get_sla_shift_z();
const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix();
::glPushMatrix();
::glTranslated(0.0, 0.0, z_shift);
::glMultMatrixd(instance_matrix.data());
float render_color[3];
for (int i = 0; i < (int)m_grabbers.size(); ++i)
for (int i = 0; i < (int)m_editing_mode_cache.size(); ++i)
{
// first precalculate the grabber position in world coordinates, so that the grabber
// is not scaled with the object (as it would be if rendered with current gl matrix).
Eigen::Matrix<GLfloat, 4, 4> glmatrix;
glGetFloatv (GL_MODELVIEW_MATRIX, glmatrix.data());
Eigen::Matrix<float, 4, 1> grabber_pos;
for (int j=0; j<3; ++j)
grabber_pos(j) = m_grabbers[i].center(j);
grabber_pos[3] = 1.f;
Eigen::Matrix<float, 4, 1> grabber_world_position = glmatrix * grabber_pos;
const sla::SupportPoint& support_point = m_editing_mode_cache[i].first;
const bool& point_selected = m_editing_mode_cache[i].second;
if (!picking && (m_hover_id == i))
{
render_color[0] = 1.0f - m_grabbers[i].color[0];
render_color[1] = 1.0f - m_grabbers[i].color[1];
render_color[2] = 1.0f - m_grabbers[i].color[2];
// First decide about the color of the point.
if (picking) {
render_color[0] = 1.0f;
render_color[1] = 1.0f;
render_color[2] = picking_color_component(i);
}
else {
if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active
render_color[0] = 0.f;
render_color[1] = 1.0f;
render_color[2] = 1.0f;
}
else { // neigher hover nor picking
bool supports_new_island = m_lock_unique_islands && m_editing_mode_cache[i].first.is_new_island;
if (m_editing_mode) {
render_color[0] = point_selected ? 1.0f : (supports_new_island ? 0.3f : 0.7f);
render_color[1] = point_selected ? 0.3f : (supports_new_island ? 0.3f : 0.7f);
render_color[2] = point_selected ? 0.3f : (supports_new_island ? 1.0f : 0.7f);
}
else
for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f;
}
}
else
::memcpy((void*)render_color, (const void*)m_grabbers[i].color, 3 * sizeof(float));
::glColor3fv(render_color);
float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f};
::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive);
// Now render the sphere. Inverse matrix of the instance scaling is applied so that the
// sphere does not scale with the object.
::glPushMatrix();
::glLoadIdentity();
::glTranslated(grabber_world_position(0), grabber_world_position(1), grabber_world_position(2) + z_shift);
const float diameter = 0.8f;
::gluSphere(m_quadric, diameter/2.f, 64, 36);
::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2));
::glMultMatrixd(instance_scaling_matrix_inverse.data());
::gluSphere(m_quadric, m_editing_mode_cache[i].first.head_front_radius * RenderPointScale, 64, 36);
::glPopMatrix();
}
{
// Reset emissive component to zero (the default value)
float render_color_emissive[4] = { 0.f, 0.f, 0.f, 1.f };
::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive);
}
if (!picking)
::glDisable(GL_LIGHTING);
::glPopMatrix();
}
#else
void GLGizmoSlaSupports::render_grabbers(bool picking) const
{
if (m_parent.get_selection().is_empty())
return;
float z_shift = m_parent.get_selection().get_volume(0)->get_sla_shift_z();
::glTranslatef((GLfloat)0, (GLfloat)0, (GLfloat)z_shift);
int selected_instance = m_parent.get_selection().get_instance_idx();
assert(selected_instance < (int)m_model_object->instances.size());
float render_color_inactive[3] = { 0.5f, 0.5f, 0.5f };
for (const ModelInstance* inst : m_model_object->instances) {
bool active = inst == m_model_object->instances[selected_instance];
if (picking && ! active)
continue;
for (int i = 0; i < (int)m_grabbers.size(); ++i)
{
if (!m_grabbers[i].enabled)
continue;
float render_color[3];
if (! picking && active && m_hover_id == i) {
render_color[0] = 1.0f - m_grabbers[i].color[0];
render_color[1] = 1.0f - m_grabbers[i].color[1];
render_color[2] = 1.0f - m_grabbers[i].color[2];
}
else
::memcpy((void*)render_color, active ? (const void*)m_grabbers[i].color : (const void*)render_color_inactive, 3 * sizeof(float));
if (!picking)
::glEnable(GL_LIGHTING);
::glColor3f((GLfloat)render_color[0], (GLfloat)render_color[1], (GLfloat)render_color[2]);
::glPushMatrix();
Vec3d center = inst->get_matrix() * m_grabbers[i].center;
::glTranslatef((GLfloat)center(0), (GLfloat)center(1), (GLfloat)center(2));
GLUquadricObj *quadric;
quadric = ::gluNewQuadric();
::gluQuadricDrawStyle(quadric, GLU_FILL );
::gluSphere( quadric , 0.4, 64 , 32 );
::gluDeleteQuadric(quadric);
::glPopMatrix();
if (!picking)
::glDisable(GL_LIGHTING);
}
}
::glTranslatef((GLfloat)0, (GLfloat)0, (GLfloat)-z_shift);
}
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
bool GLGizmoSlaSupports::is_mesh_update_necessary() const
{
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
return (m_state == On) && (m_model_object != nullptr) && (m_model_object != m_old_model_object) && !m_model_object->instances.empty();
#else
return m_state == On && m_model_object && !m_model_object->instances.empty() && !m_instance_matrix.isApprox(m_source_data.matrix);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
//if (m_state != On || !m_model_object || m_model_object->instances.empty() || ! m_instance_matrix.isApprox(m_source_data.matrix))
// return false;
@ -2027,27 +1972,14 @@ void GLGizmoSlaSupports::update_mesh()
m_AABB = igl::AABB<Eigen::MatrixXf,3>();
m_AABB.init(m_V, m_F);
#if !ENABLE_SLA_SUPPORT_GIZMO_MOD
m_source_data.matrix = m_instance_matrix;
#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD
// we'll now reload Grabbers (selection might have changed):
m_grabbers.clear();
for (const Vec3f& point : m_model_object->sla_support_points) {
m_grabbers.push_back(Grabber());
m_grabbers.back().center = point.cast<double>();
}
// we'll now reload support points (selection might have changed):
editing_mode_reload_cache();
}
Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
{
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
if (m_V.size() == 0)
#else
if (m_V.size() == 0 || is_mesh_update_necessary())
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
update_mesh();
Eigen::Matrix<GLint, 4, 1, Eigen::DontAlign> viewport;
@ -2064,20 +1996,15 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
igl::Hit hit;
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
const GLCanvas3D::Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
double z_offset = volume->get_sla_shift_z();
#else
double z_offset = m_parent.get_selection().get_volume(0)->get_sla_shift_z();
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
point1(2) -= z_offset;
point2(2) -= z_offset;
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
Transform3d inv = volume->get_instance_transformation().get_matrix().inverse();
#else
Transform3d inv = m_instance_matrix.inverse();
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
point1 = inv * point1;
point2 = inv * point2;
@ -2089,68 +2016,174 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
return bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2));
}
void GLGizmoSlaSupports::clicked_on_object(const Vec2d& mouse_position)
// 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
// concludes that the event was not intended for it, it should return false.
bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down)
{
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
int instance_id = m_parent.get_selection().get_instance_idx();
if (m_old_instance_id != instance_id)
{
bool something_selected = (m_old_instance_id != -1);
m_old_instance_id = instance_id;
if (something_selected)
return;
if (!m_editing_mode)
return false;
// left down - show the selection rectangle:
if (action == SLAGizmoEventType::LeftDown && shift_down) {
if (m_hover_id == -1) {
m_selection_rectangle_active = true;
m_selection_rectangle_start_corner = mouse_position;
m_selection_rectangle_end_corner = mouse_position;
m_canvas_width = m_parent.get_canvas_size().get_width();
m_canvas_height = m_parent.get_canvas_size().get_height();
}
else
select_point(m_hover_id);
return true;
}
if (instance_id == -1)
return;
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
Vec3f new_pos;
try {
new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new grabber in that case
// dragging the selection rectangle:
if (action == SLAGizmoEventType::Dragging && m_selection_rectangle_active) {
m_selection_rectangle_end_corner = mouse_position;
return true;
}
catch (...) { return; }
m_grabbers.push_back(Grabber());
m_grabbers.back().center = new_pos.cast<double>();
m_model_object->sla_support_points.push_back(new_pos);
// mouse up without selection rectangle - place point on the mesh:
if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle_active && !shift_down) {
if (m_ignore_up_event) {
m_ignore_up_event = false;
return false;
}
// This should trigger the support generation
// wxGetApp().plater()->reslice();
int instance_id = m_parent.get_selection().get_instance_idx();
if (m_old_instance_id != instance_id)
{
bool something_selected = (m_old_instance_id != -1);
m_old_instance_id = instance_id;
if (something_selected)
return false;
}
if (instance_id == -1)
return false;
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
// Regardless of whether the user clicked the object or not, we will unselect all points:
select_point(NoPoints);
Vec3f new_pos;
try {
new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case
m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), true));
m_unsaved_changes = true;
}
catch (...) { // not clicked on object
return true; // prevents deselection of the gizmo by GLCanvas3D
}
return true;
}
// left up with selection rectangle - select points inside the rectangle:
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp)
&& m_selection_rectangle_active) {
if (action == SLAGizmoEventType::ShiftUp)
m_ignore_up_event = true;
const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix();
GLint viewport[4];
::glGetIntegerv(GL_VIEWPORT, viewport);
GLdouble modelview_matrix[16];
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
GLdouble projection_matrix[16];
::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
const GLCanvas3D::Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
double z_offset = volume->get_sla_shift_z();
// bounding box created from the rectangle corners - will take care of order of the corners
BoundingBox rectangle(Points{Point(m_selection_rectangle_start_corner.cast<int>()), Point(m_selection_rectangle_end_corner.cast<int>())});
const Transform3d& instance_matrix_no_translation = volume->get_instance_transformation().get_matrix(true);
// we'll recover current look direction from the modelview matrix (in world coords)...
Vec3f direction_to_camera(modelview_matrix[2], modelview_matrix[6], modelview_matrix[10]);
// ...and transform it to model coords.
direction_to_camera = instance_matrix_no_translation.inverse().cast<float>() * direction_to_camera.eval();
// Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh:
for (std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache) {
const sla::SupportPoint& support_point = point_and_selection.first;
Vec3f pos = instance_matrix.cast<float>() * support_point.pos;
pos(2) += z_offset;
GLdouble out_x, out_y, out_z;
::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z);
out_y = m_canvas_height - out_y;
if (rectangle.contains(Point(out_x, out_y))) {
bool is_obscured = false;
// Cast a ray in the direction of the camera and look for intersection with the mesh:
std::vector<igl::Hit> hits;
if (m_AABB.intersect_ray(m_V, m_F, support_point.pos, direction_to_camera, hits))
// FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
// Also, the threshold is in mesh coordinates, not in actual dimensions.
if (hits.size() > 1 || hits.front().t > 0.001f)
is_obscured = true;
if (!is_obscured)
point_and_selection.second = true;
}
}
m_selection_rectangle_active = false;
return true;
}
if (action == SLAGizmoEventType::Delete) {
// delete key pressed
delete_selected_points();
return true;
}
if (action == SLAGizmoEventType::RightDown) {
if (m_hover_id != -1) {
select_point(NoPoints);
select_point(m_hover_id);
delete_selected_points();
return true;
}
return false;
}
if (action == SLAGizmoEventType::SelectAll) {
select_point(AllPoints);
return true;
}
return false;
}
void GLGizmoSlaSupports::delete_current_grabber(bool delete_all)
void GLGizmoSlaSupports::delete_selected_points()
{
if (delete_all) {
m_grabbers.clear();
m_model_object->sla_support_points.clear();
// This should trigger the support generation
// wxGetApp().plater()->reslice();
}
else
if (m_hover_id != -1) {
m_grabbers.erase(m_grabbers.begin() + m_hover_id);
m_model_object->sla_support_points.erase(m_model_object->sla_support_points.begin() + m_hover_id);
m_hover_id = -1;
if (!m_editing_mode)
return;
for (unsigned int idx=0; idx<m_editing_mode_cache.size(); ++idx) {
if (m_editing_mode_cache[idx].second && (!m_editing_mode_cache[idx].first.is_new_island || !m_lock_unique_islands)) {
m_editing_mode_cache.erase(m_editing_mode_cache.begin() + (idx--));
m_unsaved_changes = true;
}
// This should trigger the support generation
// wxGetApp().plater()->reslice();
}
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
//m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
void GLGizmoSlaSupports::on_update(const UpdateData& data, const GLCanvas3D::Selection& selection)
{
if (m_hover_id != -1 && data.mouse_pos) {
if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].first.is_new_island || !m_lock_unique_islands)) {
Vec3f new_pos;
try {
new_pos = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1)));
}
catch (...) { return; }
m_grabbers[m_hover_id].center = new_pos.cast<double>();
m_model_object->sla_support_points[m_hover_id] = new_pos;
m_editing_mode_cache[m_hover_id].first.pos = new_pos;
m_editing_mode_cache[m_hover_id].first.is_new_island = false;
m_unsaved_changes = true;
// Do not update immediately, wait until the mouse is released.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
@ -2196,37 +2229,165 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas
RENDER_AGAIN:
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove |/* ImGuiWindowFlags_NoResize | */ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(100.0f);
m_imgui->text(_(L("Left mouse click - add point")));
m_imgui->text(_(L("Right mouse click - remove point")));
m_imgui->text(" ");
bool generate = m_imgui->button(_(L("Generate points automatically")));
bool remove_all_clicked = m_imgui->button(_(L("Remove all points")) + (m_model_object == nullptr ? "" : " (" + std::to_string(m_model_object->sla_support_points.size())+")"));
bool force_refresh = false;
bool remove_selected = false;
bool old_editing_state = m_editing_mode;
if (m_editing_mode) {
m_imgui->text(_(L("Left mouse click - add point")));
m_imgui->text(_(L("Right mouse click - remove point")));
m_imgui->text(_(L("Shift + Left (+ drag) - select point(s)")));
m_imgui->text(" "); // vertical gap
std::vector<wxString> options = {"0.2", "0.4", "0.6", "0.8", "1.0"};
std::stringstream ss;
ss << std::setprecision(1) << m_new_point_head_diameter;
wxString str = ss.str();
bool old_combo_state = m_combo_box_open;
m_combo_box_open = m_imgui->combo(_(L("Head diameter")), options, str);
force_refresh |= (old_combo_state != m_combo_box_open);
float current_number = atof(str);
if (old_combo_state && !m_combo_box_open) // closing the combo must always change the sizes (even if the selection did not change)
for (auto& point_and_selection : m_editing_mode_cache)
if (point_and_selection.second) {
point_and_selection.first.head_front_radius = current_number / 2.f;
m_unsaved_changes = true;
}
if (std::abs(current_number - m_new_point_head_diameter) > 0.001) {
force_refresh = true;
m_new_point_head_diameter = current_number;
}
bool changed = m_lock_unique_islands;
m_imgui->checkbox(_(L("Lock supports under new islands")), m_lock_unique_islands);
force_refresh |= changed != m_lock_unique_islands;
remove_selected = m_imgui->button(_(L("Remove selected points")));
m_imgui->text(" "); // vertical gap
bool apply_changes = m_imgui->button(_(L("Apply changes")));
if (apply_changes) {
editing_mode_apply_changes();
force_refresh = true;
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
ImGui::SameLine();
bool discard_changes = m_imgui->button(_(L("Discard changes")));
if (discard_changes) {
editing_mode_discard_changes();
force_refresh = true;
}
}
else {
/* ImGui::PushItemWidth(50.0f);
m_imgui->text(_(L("Minimal points distance: ")));
ImGui::SameLine();
bool value_changed = ImGui::InputDouble("mm", &m_minimal_point_distance, 0.0f, 0.0f, "%.2f");
m_imgui->text(_(L("Support points density: ")));
ImGui::SameLine();
value_changed |= ImGui::InputDouble("%", &m_density, 0.0f, 0.0f, "%.f");*/
bool generate = m_imgui->button(_(L("Auto-generate points")));
if (generate) {
#if SLAGIZMO_IMGUI_MODAL
ImGui::OpenPopup(_(L("Warning")));
m_show_modal = true;
force_refresh = true;
#else
wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L(
"Autogeneration will erase all manually edited points.\n\n"
"Are you sure you want to do it?\n"
)), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) {
m_model_object->sla_support_points.clear();
m_editing_mode_cache.clear();
wxGetApp().plater()->reslice();
}
#endif
}
#if SLAGIZMO_IMGUI_MODAL
if (m_show_modal) {
if (ImGui::BeginPopupModal(_(L("Warning")), &m_show_modal/*, ImGuiWindowFlags_NoDecoration*/))
{
m_imgui->text(_(L("Autogeneration will erase all manually edited points.")));
m_imgui->text("");
m_imgui->text(_(L("Are you sure you want to do it?")));
if (m_imgui->button(_(L("Continue"))))
{
ImGui::CloseCurrentPopup();
m_show_modal = false;
m_model_object->sla_support_points.clear();
m_editing_mode_cache.clear();
wxGetApp().plater()->reslice();
}
ImGui::SameLine();
if (m_imgui->button(_(L("Cancel")))) {
ImGui::CloseCurrentPopup();
m_show_modal = false;
}
ImGui::EndPopup();
}
if (!m_show_modal)
force_refresh = true;
}
#endif
m_imgui->text("");
m_imgui->text("");
bool editing_clicked = m_imgui->button(_(L("Manual editing")));
if (editing_clicked) {
editing_mode_reload_cache();
m_editing_mode = true;
}
}
m_imgui->end();
if (remove_all_clicked) {
delete_current_grabber(true);
if (m_editing_mode != old_editing_state) { // user just toggled between editing/non-editing mode
m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode);
force_refresh = true;
}
if (remove_selected) {
force_refresh = false;
m_parent.reload_scene(true);
delete_selected_points();
if (first_run) {
first_run = false;
goto RENDER_AGAIN;
}
}
if (remove_all_clicked || generate) {
if (force_refresh)
m_parent.reload_scene(true);
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
}
#endif // ENABLE_IMGUI
bool GLGizmoSlaSupports::on_is_activable(const GLCanvas3D::Selection& selection) const
{
return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA)
&& selection.is_from_single_instance();
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA
|| !selection.is_from_single_instance())
return false;
// Check that none of the selected volumes is outside.
const GLCanvas3D::Selection::IndicesList& list = selection.get_volume_idxs();
for (const auto& idx : list)
if (selection.get_volume(idx)->is_outside)
return false;
return true;
}
bool GLGizmoSlaSupports::on_is_selectable() const
@ -2239,6 +2400,105 @@ std::string GLGizmoSlaSupports::on_get_name() const
return L("SLA Support Points [L]");
}
void GLGizmoSlaSupports::on_set_state()
{
if (m_state == On) {
if (is_mesh_update_necessary())
update_mesh();
m_parent.toggle_model_objects_visibility(false);
if (m_model_object)
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
}
if (m_state == Off) {
if (m_old_state != Off && m_model_object) { // the gizmo was just turned Off
if (m_unsaved_changes) {
wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L("Do you want to save your manually edited support points ?\n")),
_(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES)
editing_mode_apply_changes();
else
editing_mode_discard_changes();
}
m_parent.toggle_model_objects_visibility(true);
m_editing_mode = false; // so it is not active next time the gizmo opens
#if SLAGIZMO_IMGUI_MODAL
if (m_show_modal) {
m_show_modal = false;
on_render_input_window(0,0,m_parent.get_selection()); // this is necessary to allow ImGui to terminate the modal dialog correctly
}
#endif
}
}
m_old_state = m_state;
}
void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selection)
{
if (m_hover_id != -1) {
select_point(NoPoints);
select_point(m_hover_id);
}
}
void GLGizmoSlaSupports::select_point(int i)
{
if (i == AllPoints || i == NoPoints) {
for (auto& point_and_selection : m_editing_mode_cache)
point_and_selection.second = ( i == AllPoints ? true : false);
}
else
m_editing_mode_cache[i].second = true;
}
void GLGizmoSlaSupports::editing_mode_discard_changes()
{
m_editing_mode_cache.clear();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode = false;
m_unsaved_changes = false;
}
void GLGizmoSlaSupports::editing_mode_apply_changes()
{
// If there are no changes, don't touch the front-end. The data in the cache could have been
// taken from the backend and copying them to ModelObject would needlessly invalidate them.
if (m_unsaved_changes) {
m_model_object->sla_support_points.clear();
for (const std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache)
m_model_object->sla_support_points.push_back(point_and_selection.first);
}
m_editing_mode = false;
m_unsaved_changes = false;
}
void GLGizmoSlaSupports::editing_mode_reload_cache()
{
m_editing_mode_cache.clear();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_unsaved_changes = false;
}
void GLGizmoSlaSupports::get_data_from_backend()
{
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
if (po->model_object()->id() == m_model_object->id()) {
const std::vector<sla::SupportPoint>& points = po->get_support_points();
auto mat = po->trafo().inverse().cast<float>();
for (unsigned int i=0; i<points.size();++i)
m_editing_mode_cache.emplace_back(sla::SupportPoint(mat * points[i].pos, points[i].head_front_radius, points[i].is_new_island), false);
break;
}
}
m_unsaved_changes = false;
// We don't copy the data into ModelObject, as this would stop the background processing.
}
// GLGizmoCut

View file

@ -437,31 +437,26 @@ protected:
}
};
#define SLAGIZMO_IMGUI_MODAL 0
class GLGizmoSlaSupports : public GLGizmoBase
{
private:
ModelObject* m_model_object = nullptr;
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
ModelObject* m_old_model_object = nullptr;
int m_active_instance = -1;
int m_old_instance_id = -1;
#else
Transform3d m_instance_matrix;
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
Vec3f unproject_on_mesh(const Vec2d& mouse_pos);
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
GLUquadricObj* m_quadric;
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
const float RenderPointScale = 1.f;
GLUquadricObj* m_quadric;
Eigen::MatrixXf m_V; // vertices
Eigen::MatrixXi m_F; // facets indices
igl::AABB<Eigen::MatrixXf,3> m_AABB;
struct SourceDataSummary {
#if !ENABLE_SLA_SUPPORT_GIZMO_MOD
BoundingBoxf3 bounding_box;
Transform3d matrix;
#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD
Vec3d mesh_first_point;
};
@ -472,14 +467,10 @@ private:
public:
explicit GLGizmoSlaSupports(GLCanvas3D& parent);
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
virtual ~GLGizmoSlaSupports();
void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection);
#else
void set_model_object_ptr(ModelObject* model_object);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
void clicked_on_object(const Vec2d& mouse_position);
void delete_current_grabber(bool delete_all);
bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down);
void delete_selected_points();
private:
bool on_init();
@ -487,11 +478,8 @@ private:
virtual void on_render(const GLCanvas3D::Selection& selection) const;
virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const;
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
void render_grabbers(const GLCanvas3D::Selection& selection, bool picking = false) const;
#else
void render_grabbers(bool picking = false) const;
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
void render_selection_rectangle() const;
void render_points(const GLCanvas3D::Selection& selection, bool picking = false) const;
bool is_mesh_update_necessary() const;
void update_mesh();
@ -501,12 +489,41 @@ private:
mutable GLTexture m_reset_texture;
#endif // not ENABLE_IMGUI
bool m_lock_unique_islands = false;
bool m_editing_mode = false;
float m_new_point_head_diameter = 0.4f;
double m_minimal_point_distance = 20.;
double m_density = 100.;
std::vector<std::pair<sla::SupportPoint, bool>> m_editing_mode_cache; // a support point and whether it is currently selected
bool m_selection_rectangle_active = false;
Vec2d m_selection_rectangle_start_corner;
Vec2d m_selection_rectangle_end_corner;
bool m_ignore_up_event = false;
bool m_combo_box_open = false;
bool m_unsaved_changes = false;
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
#if SLAGIZMO_IMGUI_MODAL
bool m_show_modal = false;
#endif
int m_canvas_width;
int m_canvas_height;
// Methods that do the model_object and editing cache synchronization,
// editing mode selection, etc:
enum {
AllPoints = -2,
NoPoints,
};
void select_point(int i);
void editing_mode_apply_changes();
void editing_mode_discard_changes();
void editing_mode_reload_cache();
void get_data_from_backend();
protected:
void on_set_state() override {
if (m_state == On && is_mesh_update_necessary()) {
update_mesh();
}
}
void on_set_state() override;
void on_start_dragging(const GLCanvas3D::Selection& selection) override;
#if ENABLE_IMGUI
virtual void on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection) override;

View file

@ -155,6 +155,12 @@ bool ImGuiWrapper::button(const wxString &label)
return ImGui::Button(label_utf8.c_str());
}
bool ImGuiWrapper::radio_button(const wxString &label, bool active)
{
auto label_utf8 = into_u8(label);
return ImGui::RadioButton(label_utf8.c_str(), active);
}
bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format)
{
return ImGui::InputDouble(label.c_str(), const_cast<double*>(&value), 0.0f, 0.0f, format.c_str());
@ -191,6 +197,28 @@ void ImGuiWrapper::text(const wxString &label)
ImGui::Text(label_utf8.c_str(), NULL);
}
bool ImGuiWrapper::combo(const wxString& label, const std::vector<wxString>& options, wxString& selection)
{
std::string selection_u8 = into_u8(selection);
// this is to force the label to the left of the widget:
text(label);
ImGui::SameLine();
if (ImGui::BeginCombo("", selection_u8.c_str())) {
for (const wxString& option : options) {
std::string option_u8 = into_u8(option);
bool is_selected = (selection_u8.empty()) ? false : (option_u8 == selection_u8);
if (ImGui::Selectable(option_u8.c_str(), is_selected))
selection = option_u8;
}
ImGui::EndCombo();
return true;
}
return false;
}
void ImGuiWrapper::disabled_begin(bool disabled)
{
wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call");

View file

@ -49,10 +49,12 @@ public:
void end();
bool button(const wxString &label);
bool radio_button(const wxString &label, bool active);
bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f");
bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f");
bool checkbox(const wxString &label, bool &value);
void text(const wxString &label);
bool combo(const wxString& label, const std::vector<wxString>& options, wxString& current_selection);
void disabled_begin(bool disabled);
void disabled_end();

View file

@ -2244,6 +2244,10 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
break;
}
}
if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS) {
// Update SLA gizmo (reload_scene calls update_gizmos_data)
q->canvas3D()->reload_scene(true);
}
}
void Plater::priv::on_slicing_completed(wxCommandEvent &)

View file

@ -457,9 +457,8 @@ const std::vector<std::string>& Preset::sla_print_options()
"support_critical_angle",
"support_max_bridge_length",
"support_object_elevation",
"support_density_at_horizontal",
"support_density_at_45",
"support_minimal_z",
"support_points_density_relative",
"support_points_minimal_distance",
"pad_enable",
"pad_wall_thickness",
"pad_wall_height",

View file

@ -3,6 +3,8 @@
#include "3DScene.hpp"
#include "GUI.hpp"
#include <string>
#include <wx/clipbrd.h>
#include <wx/platinfo.h>

View file

@ -3202,9 +3202,8 @@ void TabSLAPrint::build()
optgroup->append_single_option_line("support_max_bridge_length");
optgroup = page->new_optgroup(_(L("Automatic generation")));
optgroup->append_single_option_line("support_density_at_horizontal");
optgroup->append_single_option_line("support_density_at_45");
optgroup->append_single_option_line("support_minimal_z");
optgroup->append_single_option_line("support_points_density_relative");
optgroup->append_single_option_line("support_points_minimal_distance");
page = add_options_page(_(L("Pad")), "brick.png");
optgroup = page->new_optgroup(_(L("Pad")));