Multiple beds (part 5):

- nicer active / virtual bed visualization
- select bed by left mouse click
- bed selector only shows in preview
This commit is contained in:
Lukas Matena 2024-10-03 08:41:19 +02:00
parent 9035caa337
commit c24e9fdfed
6 changed files with 83 additions and 35 deletions

View File

@ -39,6 +39,9 @@ public:
int get_thumbnail_bed_idx() const { return m_bed_for_thumbnails_generation; }
bool is_glvolume_on_thumbnail_bed(const Model& model, int obj_idx, int instance_idx) const;
void set_last_hovered_bed(int i) { m_last_hovered_bed = i; }
int get_last_hovered_bed() const { return m_last_hovered_bed; }
private:
@ -52,7 +55,7 @@ private:
bool m_show_next_bed = false;
std::map<ObjectID, int> m_inst_to_bed;
std::map<PrintBase*, size_t> m_printbase_to_texture;
int m_last_hovered_bed = -1;
};
extern MultipleBeds s_multiple_beds;

View File

@ -110,7 +110,7 @@ void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Tra
{
bool is_thumbnail = s_multiple_beds.get_thumbnail_bed_idx() != -1;
bool is_preview = wxGetApp().plater()->is_preview_shown();
int bed_to_highlight = -1;
int bed_to_highlight = s_multiple_beds.get_active_bed();
static std::vector<int> beds_to_render;
beds_to_render.clear();
@ -121,14 +121,12 @@ void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Tra
else {
beds_to_render.resize(s_multiple_beds.get_number_of_beds() + int(s_multiple_beds.should_show_next_bed()));
std::iota(beds_to_render.begin(), beds_to_render.end(), 0);
if (s_multiple_beds.get_number_of_beds() != 1)
bed_to_highlight = s_multiple_beds.get_active_bed();
}
for (int i : beds_to_render) {
Transform3d mat = view_matrix;
mat.translate(s_multiple_beds.get_bed_translation(i));
render_internal(canvas, mat, projection_matrix, bottom, scale_factor, show_texture, false, i == bed_to_highlight);
render_internal(canvas, mat, projection_matrix, bottom, scale_factor, show_texture, false, is_thumbnail || i == bed_to_highlight);
}
}
@ -150,9 +148,9 @@ void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix,
switch (m_type)
{
case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom, show_texture); break; }
case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom, show_texture, active); break; }
default:
case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom, show_texture, picking); break; }
case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom, show_texture, picking, active); break; }
}
glsafe(::glDisable(GL_DEPTH_TEST));
@ -335,18 +333,18 @@ void Bed3D::render_axes()
m_axes.render(Transform3d::Identity(), 0.25f);
}
void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture)
void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool is_active)
{
if (!bottom)
render_model(view_matrix, projection_matrix);
if (show_texture)
render_texture(bottom, canvas, view_matrix, projection_matrix);
render_texture(bottom, canvas, view_matrix, projection_matrix, is_active);
else if (bottom)
render_contour(view_matrix, projection_matrix);
}
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix)
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool is_active)
{
if (m_texture_filename.empty()) {
m_texture.reset();
@ -414,7 +412,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& v
shader->start_using();
shader->set_uniform("view_model_matrix", view_matrix);
shader->set_uniform("projection_matrix", projection_matrix);
shader->set_uniform("transparent_background", bottom);
shader->set_uniform("transparent_background", bottom || ! is_active);
shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg"));
glsafe(::glEnable(GL_DEPTH_TEST));
@ -489,7 +487,7 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj
}
}
void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking)
void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking, bool is_active)
{
if (m_texture_filename.empty() && m_model_filename.empty()) {
render_default(bottom, picking, show_texture, view_matrix, projection_matrix);
@ -500,7 +498,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, co
render_model(view_matrix, projection_matrix);
if (show_texture)
render_texture(bottom, canvas, view_matrix, projection_matrix);
render_texture(bottom, canvas, view_matrix, projection_matrix, is_active);
else if (bottom)
render_contour(view_matrix, projection_matrix);
}

View File

@ -87,10 +87,10 @@ private:
static std::tuple<Type, std::string, std::string> detect_type(const Pointfs& shape);
void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
bool show_texture, bool picking, bool active);
void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture);
void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix);
void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool is_active);
void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool is_active);
void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix);
void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking);
void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking, bool is_active);
void render_default(bool bottom, bool picking, bool show_texture, const Transform3d& view_matrix, const Transform3d& projection_matrix);
void render_contour(const Transform3d& view_matrix, const Transform3d& projection_matrix);

View File

@ -102,6 +102,24 @@ static bool show_imgui_demo_window = false;
namespace Slic3r {
namespace GUI {
static void select_bed(int i)
{
int old_bed = s_multiple_beds.get_active_bed();
if (i == old_bed || i == -1)
return;
s_multiple_beds.set_active_bed(i);
if (wxGetApp().plater()->is_preview_shown()) {
s_reload_preview_after_switching_beds = true;
wxPostEvent(wxGetApp().plater(), SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW));
wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed));
}
wxGetApp().plater()->sidebar().update_sliced_info_sizer();
}
#ifdef __WXGTK3__
// wxGTK3 seems to simulate OSX behavior in regard to HiDPI scaling support.
RetinaHelper::RetinaHelper(wxWindow* window) : m_window(window), m_self(nullptr) {}
@ -1460,7 +1478,6 @@ bool GLCanvas3D::check_volumes_outside_state(GLVolumeCollection& volumes, ModelI
bool contained_min_one = false;
const Slic3r::BuildVolume& build_volume = m_bed.build_volume();
s_multiple_beds.request_next_bed(false);
const std::vector<unsigned int> volumes_idxs = volumes_to_process_idxs();
for (unsigned int vol_idx : volumes_idxs) {
@ -1834,22 +1851,14 @@ void GLCanvas3D::render()
{
if (s_multiple_beds.get_number_of_beds() != 1) {
if (s_multiple_beds.get_number_of_beds() != 1 && wxGetApp().plater()->is_preview_shown()) {
ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize);
for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) {
bool inactive = i != s_multiple_beds.get_active_bed();
if (inactive)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5));
if (ImGui::ImageButton((void*)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0))) {
int old_bed = s_multiple_beds.get_active_bed();
s_multiple_beds.set_active_bed(i);
if (wxGetApp().plater()->is_preview_shown()) {
s_reload_preview_after_switching_beds = true;
wxPostEvent(wxGetApp().plater(), SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW));
camera.translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed));
}
wxGetApp().plater()->sidebar().update_sliced_info_sizer();
}
if (ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0)))
select_bed(i);
if (inactive)
ImGui::PopStyleColor();
}
@ -3281,10 +3290,11 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt)
void GLCanvas3D::on_render_timer(wxTimerEvent& evt)
{
m_dirty = true;
// no need to wake up idle
// right after this event, idle event is fired
// m_dirty = true;
// wxWakeUpIdle();
//wxWakeUpIdle();
}
@ -3376,6 +3386,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
Point pos(evt.GetX(), evt.GetY());
static wxTimer s_virtual_bed_timer;
s_virtual_bed_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) { s_multiple_beds.request_next_bed(true); schedule_extra_frame(100); });
ImGuiWrapper* imgui = wxGetApp().imgui();
if (m_tooltip.is_in_imgui() && evt.LeftUp())
// ignore left up events coming from imgui windows and not processed by them
@ -3613,6 +3626,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
m_dirty = true;
}
} else if (evt.LeftDown()) {
select_bed(s_multiple_beds.get_last_hovered_bed());
}
}
@ -3640,6 +3655,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.Dragging() && evt.LeftIsDown() && !evt.CmdDown() && m_layers_editing.state == LayersEditing::Unknown &&
m_mouse.drag.move_volume_idx != -1 && m_mouse.is_start_position_3D_defined()) {
if (!m_mouse.drag.move_requires_threshold) {
static bool was_dragging = false;
was_dragging = m_mouse.dragging;
m_mouse.dragging = true;
Vec3d cur_pos = m_mouse.drag.start_position_3D;
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
@ -3682,6 +3699,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
update_sequential_clearance(false);
wxGetApp().obj_manipul()->set_dirty();
m_dirty = true;
const Selection::IndicesList& list = m_selection.get_volume_idxs();
static bool was_outside = true;
bool is_outside = std::any_of(list.begin(), list.end(), [this](unsigned int i) { return m_volumes.volumes[i]->is_outside; });
if (is_outside && (! was_dragging || ! was_outside))
s_virtual_bed_timer.Start(1000, true);
was_outside = is_outside;
}
}
else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) {
@ -3754,6 +3778,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_layers_editing.accept_changes(*this);
}
else if (m_mouse.drag.move_volume_idx != -1 && m_mouse.dragging) {
s_multiple_beds.request_next_bed(false);
s_virtual_bed_timer.Stop();
do_move(L("Move Object"));
wxGetApp().obj_manipul()->set_dirty();
m_sequential_print_clearance.stop_dragging();

View File

@ -2052,8 +2052,8 @@ void Plater::priv::scale_selection_to_fit_print_volume()
void Plater::priv::schedule_background_process()
{
delayed_error_message.clear();
// Trigger the timer event after 0.5s
this->background_process_timer.Start(500, wxTIMER_ONE_SHOT);
// Trigger the timer event after 0.1s
this->background_process_timer.Start(100, wxTIMER_ONE_SHOT);
// Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff.
this->view3D->get_canvas3d()->set_config(this->config);
}
@ -3277,7 +3277,8 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
if (evt.data.second) { // right button was clicked on empty space
if (!get_selection().is_empty()) // several objects are selected in 3DScene
return;
menu = menus.default_menu();
if (s_multiple_beds.get_last_hovered_bed() != -1)
menu = menus.default_menu();
}
else
menu = menus.multi_selection_menu();

View File

@ -10,6 +10,8 @@
#include "Selection.hpp"
#include "Plater.hpp"
#include "libslic3r/MultipleBeds.hpp"
namespace Slic3r {
namespace GUI {
@ -164,9 +166,27 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came
if (!item->is_active())
continue;
bool sth_hit = false;
current_hit.raycaster_id = item->get_id();
const Transform3d& trafo = item->get_transform();
if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) {
const Transform3d& trafo_orig = item->get_transform();
Transform3d trafo = trafo_orig;
if (type == EType::Bed) {
int bed_idx_hit = -1;
for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) {
trafo = trafo_orig;
trafo.translate(s_multiple_beds.get_bed_translation(i));
sth_hit = item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane);
if (sth_hit) {
bed_idx_hit = i;
break;
}
}
s_multiple_beds.set_last_hovered_bed(bed_idx_hit);
} else
sth_hit = item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane);
if (sth_hit) {
current_hit.position = (trafo * current_hit.position.cast<double>()).cast<float>();
current_hit.normal = (trafo.matrix().block(0, 0, 3, 3).inverse().transpose() * current_hit.normal.cast<double>()).normalized().cast<float>();
if (item->use_back_faces() || current_hit.normal.dot(camera_forward) < 0.0f) {