Rectangle selection in 3D scene -> hovering detection
This commit is contained in:
parent
ec2f319a3d
commit
11490dfb06
6 changed files with 148 additions and 26 deletions
|
@ -223,7 +223,8 @@ void GLIndexedVertexArray::render(
|
|||
}
|
||||
|
||||
const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
|
||||
const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||
const float GLVolume::HOVER_SELECT_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||
const float GLVolume::HOVER_DESELECT_COLOR[4] = { 0.9f, 0.4f, 0.1f, 1.0f };
|
||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
||||
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
|
||||
|
@ -251,7 +252,8 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
|||
, zoom_to_volumes(true)
|
||||
, shader_outside_printer_detection_enabled(false)
|
||||
, is_outside(false)
|
||||
, hover(false)
|
||||
, hover_select(false)
|
||||
, hover_deselect(false)
|
||||
, is_modifier(false)
|
||||
, is_wipe_tower(false)
|
||||
, is_extrusion_path(false)
|
||||
|
@ -291,10 +293,12 @@ void GLVolume::set_render_color()
|
|||
if (force_native_color)
|
||||
set_render_color(color, 4);
|
||||
else {
|
||||
if (selected)
|
||||
if (hover_select)
|
||||
set_render_color(HOVER_SELECT_COLOR, 4);
|
||||
else if (hover_deselect)
|
||||
set_render_color(HOVER_DESELECT_COLOR, 4);
|
||||
else if (selected)
|
||||
set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
|
||||
else if (hover)
|
||||
set_render_color(HOVER_COLOR, 4);
|
||||
else if (disabled)
|
||||
set_render_color(DISABLED_COLOR, 4);
|
||||
else if (is_outside && shader_outside_printer_detection_enabled)
|
||||
|
|
|
@ -225,7 +225,8 @@ private:
|
|||
class GLVolume {
|
||||
public:
|
||||
static const float SELECTED_COLOR[4];
|
||||
static const float HOVER_COLOR[4];
|
||||
static const float HOVER_SELECT_COLOR[4];
|
||||
static const float HOVER_DESELECT_COLOR[4];
|
||||
static const float OUTSIDE_COLOR[4];
|
||||
static const float SELECTED_OUTSIDE_COLOR[4];
|
||||
static const float DISABLED_COLOR[4];
|
||||
|
@ -296,8 +297,10 @@ public:
|
|||
bool shader_outside_printer_detection_enabled;
|
||||
// Wheter or not this volume is outside print volume.
|
||||
bool is_outside;
|
||||
// Boolean: Is mouse over this object?
|
||||
bool hover;
|
||||
// Boolean: Is mouse over this object to select it ?
|
||||
bool hover_select;
|
||||
// Boolean: Is mouse over this object to deselect it ?
|
||||
bool hover_deselect;
|
||||
// Wheter or not this volume has been generated from a modifier
|
||||
bool is_modifier;
|
||||
// Wheter or not this volume has been generated from the wipe tower
|
||||
|
|
|
@ -1610,7 +1610,11 @@ void GLCanvas3D::render()
|
|||
|
||||
wxGetApp().imgui()->new_frame();
|
||||
|
||||
// picking pass
|
||||
if (m_rectangle_selection.is_dragging())
|
||||
// picking pass using rectangle selection
|
||||
_rectangular_selection_picking_pass();
|
||||
else
|
||||
// regular picking pass
|
||||
_picking_pass();
|
||||
|
||||
// draw scene
|
||||
|
@ -2361,6 +2365,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
}
|
||||
set_cursor(Standard);
|
||||
}
|
||||
else if (keyCode == WXK_CONTROL)
|
||||
m_dirty = true;
|
||||
}
|
||||
else if (evt.GetEventType() == wxEVT_KEY_DOWN) {
|
||||
m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers();
|
||||
|
@ -2374,6 +2380,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports))
|
||||
set_cursor(Cross);
|
||||
}
|
||||
else if (keyCode == WXK_CONTROL)
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3662,7 +3670,7 @@ void GLCanvas3D::_picking_pass() const
|
|||
if (inside)
|
||||
{
|
||||
glsafe(::glReadPixels(pos(0), cnv_size.get_height() - pos(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
|
||||
volume_id = color[0] + color[1] * 256 + color[2] * 256 * 256;
|
||||
volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
|
||||
}
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
||||
{
|
||||
|
@ -3676,6 +3684,83 @@ void GLCanvas3D::_picking_pass() const
|
|||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::_rectangular_selection_picking_pass() const
|
||||
{
|
||||
m_gizmos.set_hover_id(-1);
|
||||
|
||||
std::set<int> idxs;
|
||||
|
||||
if (m_picking_enabled)
|
||||
{
|
||||
if (m_multisample_allowed)
|
||||
glsafe(::glDisable(GL_MULTISAMPLE));
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
_render_volumes_for_picking();
|
||||
|
||||
if (m_multisample_allowed)
|
||||
glsafe(::glEnable(GL_MULTISAMPLE));
|
||||
|
||||
int width = (int)m_rectangle_selection.get_width();
|
||||
int height = (int)m_rectangle_selection.get_height();
|
||||
int px_count = width * height;
|
||||
|
||||
if (px_count > 0)
|
||||
{
|
||||
int left = (int)m_rectangle_selection.get_left();
|
||||
int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top();
|
||||
if ((left >= 0) && (top >= 0))
|
||||
{
|
||||
#define USE_PARALLEL 1
|
||||
#if USE_PARALLEL
|
||||
struct Pixel
|
||||
{
|
||||
std::array<GLubyte, 4> data;
|
||||
int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); }
|
||||
};
|
||||
|
||||
std::vector<Pixel> frame(px_count);
|
||||
glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data()));
|
||||
|
||||
tbb::spin_mutex mutex;
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, frame.size(), (size_t)width),
|
||||
[this, &frame, &idxs, &mutex](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t i = range.begin(); i < range.end(); ++i)
|
||||
{
|
||||
int volume_id = frame[i].id();
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
||||
{
|
||||
mutex.lock();
|
||||
idxs.insert(volume_id);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
#else
|
||||
std::vector<GLubyte> frame(4 * px_count);
|
||||
glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data()));
|
||||
|
||||
for (int i = 0; i < px_count; ++i)
|
||||
{
|
||||
int px_id = 4 * i;
|
||||
int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16);
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
||||
idxs.insert(volume_id);
|
||||
}
|
||||
#endif // USE_PARALLEL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_hover_volume_idxs.assign(idxs.begin(), idxs.end());
|
||||
_update_volumes_hover_state();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_background() const
|
||||
{
|
||||
glsafe(::glPushMatrix());
|
||||
|
@ -4161,15 +4246,32 @@ void GLCanvas3D::_update_volumes_hover_state() const
|
|||
{
|
||||
for (GLVolume* v : m_volumes.volumes)
|
||||
{
|
||||
v->hover = false;
|
||||
v->hover_select = false;
|
||||
v->hover_deselect = false;
|
||||
}
|
||||
|
||||
if (m_hover_volume_idxs.empty())
|
||||
return;
|
||||
|
||||
GLVolume* volume = m_volumes.volumes[get_first_hover_volume_idx()];
|
||||
if (volume->is_modifier)
|
||||
volume->hover = true;
|
||||
bool is_ctrl_pressed = wxGetKeyState(WXK_CONTROL);
|
||||
bool is_shift_pressed = wxGetKeyState(WXK_SHIFT);
|
||||
bool is_alt_pressed = wxGetKeyState(WXK_ALT);
|
||||
|
||||
for (int i : m_hover_volume_idxs)
|
||||
{
|
||||
GLVolume* volume = m_volumes.volumes[i];
|
||||
bool deselect = volume->selected && ((is_ctrl_pressed && !is_shift_pressed) || (!is_ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Deselect)));
|
||||
bool select = !volume->selected || (volume->is_modifier && ((is_ctrl_pressed && !is_alt_pressed) || (!is_ctrl_pressed && (!m_rectangle_selection.is_dragging() || (m_rectangle_selection.get_state() == GLSelectionRectangle::Select)))));
|
||||
|
||||
if (select || deselect)
|
||||
{
|
||||
if (volume->is_modifier && (!deselect || ((volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx()))))
|
||||
{
|
||||
if (deselect)
|
||||
volume->hover_deselect = true;
|
||||
else
|
||||
volume->hover_select = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int object_idx = volume->object_idx();
|
||||
|
@ -4178,7 +4280,14 @@ void GLCanvas3D::_update_volumes_hover_state() const
|
|||
for (GLVolume* v : m_volumes.volumes)
|
||||
{
|
||||
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
|
||||
v->hover = true;
|
||||
{
|
||||
if (deselect)
|
||||
v->hover_deselect = true;
|
||||
else
|
||||
v->hover_select = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -623,6 +623,7 @@ private:
|
|||
void _refresh_if_shown_on_screen();
|
||||
|
||||
void _picking_pass() const;
|
||||
void _rectangular_selection_picking_pass() const;
|
||||
void _render_background() const;
|
||||
void _render_bed(float theta) const;
|
||||
void _render_axes() const;
|
||||
|
|
|
@ -59,9 +59,7 @@ namespace GUI {
|
|||
|
||||
void GLSelectionRectangle::stop_dragging()
|
||||
{
|
||||
if (!is_dragging())
|
||||
return;
|
||||
|
||||
if (is_dragging())
|
||||
m_state = Off;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,13 @@ public:
|
|||
bool is_dragging() const { return m_state != Off; }
|
||||
EState get_state() const { return m_state; }
|
||||
|
||||
float get_width() const { return std::abs(m_start_corner(0) - m_end_corner(0)); }
|
||||
float get_height() const { return std::abs(m_start_corner(1) - m_end_corner(1)); }
|
||||
float get_left() const { return std::min(m_start_corner(0), m_end_corner(0)); }
|
||||
float get_right() const { return std::max(m_start_corner(0), m_end_corner(0)); }
|
||||
float get_top() const { return std::max(m_start_corner(1), m_end_corner(1)); }
|
||||
float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); }
|
||||
|
||||
private:
|
||||
EState m_state = Off;
|
||||
Vec2d m_start_corner;
|
||||
|
|
Loading…
Reference in a new issue