From 53914e05c6ef769271849f5556973b5d92abd3f3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 20 Aug 2018 10:23:17 +0200 Subject: [PATCH] 1st installment of gizmo rotate 3D --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 33 +- xs/src/slic3r/GUI/GLCanvas3D.hpp | 5 +- xs/src/slic3r/GUI/GLGizmo.cpp | 588 +++++++++++++++++++++++-------- xs/src/slic3r/GUI/GLGizmo.hpp | 122 +++++-- 4 files changed, 569 insertions(+), 179 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index a55ba51ae..1b24e3733 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1139,7 +1139,11 @@ bool GLCanvas3D::Gizmos::init() m_gizmos.insert(GizmosMap::value_type(Scale, gizmo)); - gizmo = new GLGizmoRotate; +#if ENABLE_GIZMOS_3D + gizmo = new GLGizmoRotate3D; +#else + gizmo = new GLGizmoRotate(GLGizmoRotate::Z); +#endif // ENABLE_GIZMOS_3D if (gizmo == nullptr) { _reset(); @@ -1294,14 +1298,14 @@ bool GLCanvas3D::Gizmos::grabber_contains_mouse() const return (curr != nullptr) ? (curr->get_hover_id() != -1) : false; } -void GLCanvas3D::Gizmos::update(const Pointf& mouse_pos) +void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray) { if (!m_enabled) return; GLGizmoBase* curr = _get_current(); if (curr != nullptr) - curr->update(mouse_pos); + curr->update(mouse_ray); } void GLCanvas3D::Gizmos::refresh() @@ -1374,7 +1378,11 @@ float GLCanvas3D::Gizmos::get_angle_z() const return 0.0f; GizmosMap::const_iterator it = m_gizmos.find(Rotate); - return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_angle_z() : 0.0f; +#if ENABLE_GIZMOS_3D + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_angle_z() : 0.0f; +#else + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_angle() : 0.0f; +#endif // ENABLE_GIZMOS_3D } void GLCanvas3D::Gizmos::set_angle_z(float angle_z) @@ -1384,7 +1392,11 @@ void GLCanvas3D::Gizmos::set_angle_z(float angle_z) GizmosMap::const_iterator it = m_gizmos.find(Rotate); if (it != m_gizmos.end()) - reinterpret_cast(it->second)->set_angle_z(angle_z); +#if ENABLE_GIZMOS_3D +reinterpret_cast(it->second)->set_angle_z(angle_z); +#else + reinterpret_cast(it->second)->set_angle(angle_z); +#endif // ENABLE_GIZMOS_3D } void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const @@ -3096,9 +3108,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.Dragging() && m_gizmos.is_dragging()) { m_mouse.dragging = true; - - const Pointf3& cur_pos = _mouse_to_bed_3d(pos); - m_gizmos.update(Pointf(cur_pos.x, cur_pos.y)); + m_gizmos.update(mouse_ray(pos)); std::vector volumes; if (m_mouse.drag.gizmo_volume_idx != -1) @@ -4128,10 +4138,15 @@ Pointf3 GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z) } Pointf3 GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos) +{ + return mouse_ray(mouse_pos).intersect_plane(0.0); +} + +Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos) { float z0 = 0.0f; float z1 = 1.0f; - return Linef3(_mouse_to_3d(mouse_pos, &z0), _mouse_to_3d(mouse_pos, &z1)).intersect_plane(0.0); + return Linef3(_mouse_to_3d(mouse_pos, &z0), _mouse_to_3d(mouse_pos, &z1)); } void GLCanvas3D::_start_timer() diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index e1b323a74..585c2526e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -365,7 +365,7 @@ public: bool overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const; bool grabber_contains_mouse() const; - void update(const Pointf& mouse_pos); + void update(const Linef3& mouse_ray); void refresh(); EType get_current_type() const; @@ -694,6 +694,9 @@ private: // Convert the screen space coordinate to world coordinate on the bed. Pointf3 _mouse_to_bed_3d(const Point& mouse_pos); + // Returns the view ray line, in world coordinate, at the given mouse position. + Linef3 mouse_ray(const Point& mouse_pos); + void _start_timer(); void _stop_timer(); diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index 7207022bd..1ee8f6f37 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -3,21 +3,28 @@ #include "../../libslic3r/Utils.hpp" #include "../../libslic3r/BoundingBox.hpp" +#include + #include #include +static const float DEFAULT_BASE_COLOR[3] = { 0.625f, 0.625f, 0.625f }; +static const float DEFAULT_DRAG_COLOR[3] = { 1.0f, 1.0f, 1.0f }; +static const float DEFAULT_HIGHLIGHT_COLOR[3] = { 1.0f, 0.38f, 0.0f }; + namespace Slic3r { namespace GUI { const float GLGizmoBase::Grabber::HalfSize = 2.0f; -const float GLGizmoBase::Grabber::HoverOffset = 0.5f; -const float GLGizmoBase::BaseColor[3] = { 1.0f, 1.0f, 1.0f }; -const float GLGizmoBase::HighlightColor[3] = { 1.0f, 0.38f, 0.0f }; +const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f; GLGizmoBase::Grabber::Grabber() - : center(Pointf(0.0, 0.0)) + : center(Pointf3(0.0, 0.0, 0.0)) + , angle_x(0.0f) + , angle_y(0.0f) , angle_z(0.0f) + , dragging(false) { color[0] = 1.0f; color[1] = 1.0f; @@ -26,17 +33,41 @@ GLGizmoBase::Grabber::Grabber() void GLGizmoBase::Grabber::render(bool hover) const { - float min_x = -HalfSize; - float max_x = +HalfSize; - float min_y = -HalfSize; - float max_y = +HalfSize; + float render_color[3]; + if (hover) + { + render_color[0] = 1.0f - color[0]; + render_color[1] = 1.0f - color[1]; + render_color[2] = 1.0f - color[2]; + } + else + ::memcpy((void*)render_color, (const void*)color, 3 * sizeof(float)); - ::glColor3f((GLfloat)color[0], (GLfloat)color[1], (GLfloat)color[2]); + render(render_color); +} + +void GLGizmoBase::Grabber::render_for_picking() const +{ + render(color); +} + +void GLGizmoBase::Grabber::render(const float* render_color) const +{ + float half_size = dragging ? HalfSize * DraggingScaleFactor : HalfSize; + float min_x = -half_size; + float max_x = +half_size; + float min_y = -half_size; + float max_y = +half_size; + + ::glColor3f((GLfloat)render_color[0], (GLfloat)render_color[1], (GLfloat)render_color[2]); - float angle_z_in_deg = angle_z * 180.0f / (float)PI; ::glPushMatrix(); - ::glTranslatef((GLfloat)center.x, (GLfloat)center.y, 0.0f); - ::glRotatef((GLfloat)angle_z_in_deg, 0.0f, 0.0f, 1.0f); + ::glTranslatef((GLfloat)center.x, (GLfloat)center.y, (GLfloat)center.z); + + float rad_to_deg = 180.0f / (GLfloat)PI; + ::glRotatef((GLfloat)angle_x * rad_to_deg, 1.0f, 0.0f, 0.0f); + ::glRotatef((GLfloat)angle_y * rad_to_deg, 0.0f, 1.0f, 0.0f); + ::glRotatef((GLfloat)angle_z * rad_to_deg, 0.0f, 0.0f, 1.0f); ::glDisable(GL_CULL_FACE); ::glBegin(GL_TRIANGLES); @@ -49,48 +80,18 @@ void GLGizmoBase::Grabber::render(bool hover) const ::glEnd(); ::glEnable(GL_CULL_FACE); - if (hover) - { - min_x -= HoverOffset; - max_x += HoverOffset; - min_y -= HoverOffset; - max_y += HoverOffset; - - ::glBegin(GL_LINE_LOOP); - ::glVertex3f((GLfloat)min_x, (GLfloat)min_y, 0.0f); - ::glVertex3f((GLfloat)max_x, (GLfloat)min_y, 0.0f); - ::glVertex3f((GLfloat)max_x, (GLfloat)max_y, 0.0f); - ::glVertex3f((GLfloat)min_x, (GLfloat)max_y, 0.0f); - ::glEnd(); - } - ::glPopMatrix(); } GLGizmoBase::GLGizmoBase() - : m_state(Off) + : m_group_id(-1) + , m_state(Off) , m_hover_id(-1) + , m_is_container(false) { -} - -GLGizmoBase::~GLGizmoBase() -{ -} - -bool GLGizmoBase::init() -{ - return on_init(); -} - -GLGizmoBase::EState GLGizmoBase::get_state() const -{ - return m_state; -} - -void GLGizmoBase::set_state(GLGizmoBase::EState state) -{ - m_state = state; - on_set_state(); + ::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 3 * sizeof(float)); + ::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 3 * sizeof(float)); + ::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 3 * sizeof(float)); } unsigned int GLGizmoBase::get_texture_id() const @@ -103,31 +104,45 @@ int GLGizmoBase::get_textures_size() const return m_textures[Off].get_width(); } -int GLGizmoBase::get_hover_id() const -{ - return m_hover_id; -} - void GLGizmoBase::set_hover_id(int id) { - if (id < (int)m_grabbers.size()) + if (m_is_container || (id < (int)m_grabbers.size())) + { m_hover_id = id; + on_set_hover_id(); + } +} + +void GLGizmoBase::set_highlight_color(const float* color) +{ + if (color != nullptr) + ::memcpy((void*)m_highlight_color, (const void*)color, 3 * sizeof(float)); } void GLGizmoBase::start_dragging() { + for (int i = 0; i < (int)m_grabbers.size(); ++i) + { + m_grabbers[i].dragging = (m_hover_id == i); + } + on_start_dragging(); } void GLGizmoBase::stop_dragging() { + for (int i = 0; i < (int)m_grabbers.size(); ++i) + { + m_grabbers[i].dragging = false; + } + on_stop_dragging(); } -void GLGizmoBase::update(const Pointf& mouse_pos) +void GLGizmoBase::update(const Linef3& mouse_ray) { if (m_hover_id != -1) - on_update(mouse_pos); + on_update(mouse_ray); } void GLGizmoBase::refresh() @@ -145,24 +160,13 @@ void GLGizmoBase::render_for_picking(const BoundingBoxf3& box) const on_render_for_picking(box); } -void GLGizmoBase::on_set_state() +float GLGizmoBase::picking_color_component(unsigned int id) const { - // do nothing -} + int color = 254 - (int)id; + if (m_group_id > -1) + color -= m_group_id; -void GLGizmoBase::on_start_dragging() -{ - // do nothing -} - -void GLGizmoBase::on_stop_dragging() -{ - // do nothing -} - -void GLGizmoBase::on_refresh() -{ - // do nothing + return (float)color / 255.0f; } void GLGizmoBase::render_grabbers() const @@ -173,54 +177,65 @@ void GLGizmoBase::render_grabbers() const } } +void GLGizmoBase::render_grabbers_for_picking() const +{ + for (int i = 0; i < (int)m_grabbers.size(); ++i) + { + m_grabbers[i].render_for_picking(); + } +} + const float GLGizmoRotate::Offset = 5.0f; const unsigned int GLGizmoRotate::CircleResolution = 64; const unsigned int GLGizmoRotate::AngleResolution = 64; -const unsigned int GLGizmoRotate::ScaleStepsCount = 60; +const unsigned int GLGizmoRotate::ScaleStepsCount = 72; const float GLGizmoRotate::ScaleStepRad = 2.0f * (float)PI / GLGizmoRotate::ScaleStepsCount; -const unsigned int GLGizmoRotate::ScaleLongEvery = 5; +const unsigned int GLGizmoRotate::ScaleLongEvery = 2; const float GLGizmoRotate::ScaleLongTooth = 2.0f; const float GLGizmoRotate::ScaleShortTooth = 1.0f; const unsigned int GLGizmoRotate::SnapRegionsCount = 8; const float GLGizmoRotate::GrabberOffset = 5.0f; -GLGizmoRotate::GLGizmoRotate() +GLGizmoRotate::GLGizmoRotate(GLGizmoRotate::Axis axis) : GLGizmoBase() - , m_angle_z(0.0f) - , m_center(Pointf(0.0, 0.0)) + , m_axis(axis) + , m_angle(0.0f) + , m_center(Pointf3(0.0, 0.0, 0.0)) , m_radius(0.0f) , m_keep_initial_values(false) { } -float GLGizmoRotate::get_angle_z() const +float GLGizmoRotate::get_angle() const { - return m_angle_z; + return m_angle; } -void GLGizmoRotate::set_angle_z(float angle_z) +void GLGizmoRotate::set_angle(float angle) { - if (std::abs(angle_z - 2.0f * PI) < EPSILON) - angle_z = 0.0f; + if (std::abs(angle - 2.0f * PI) < EPSILON) + angle = 0.0f; - m_angle_z = angle_z; + m_angle = angle; } bool GLGizmoRotate::on_init() { +#if !ENABLE_GIZMOS_3D std::string path = resources_dir() + "/icons/overlay/"; std::string filename = path + "rotate_off.png"; if (!m_textures[Off].load_from_file(filename, false)) return false; - + filename = path + "rotate_hover.png"; if (!m_textures[Hover].load_from_file(filename, false)) return false; - + filename = path + "rotate_on.png"; if (!m_textures[On].load_from_file(filename, false)) return false; +#endif // !ENABLE_GIZMOS_3D m_grabbers.push_back(Grabber()); @@ -232,16 +247,22 @@ void GLGizmoRotate::on_set_state() m_keep_initial_values = (m_state == On) ? false : true; } -void GLGizmoRotate::on_update(const Pointf& mouse_pos) +void GLGizmoRotate::on_update(const Linef3& mouse_ray) { + Pointf mouse_pos = mouse_position_in_local_plane(mouse_ray); + Vectorf orig_dir(1.0, 0.0); - Vectorf new_dir = normalize(mouse_pos - m_center); + Vectorf new_dir = normalize(mouse_pos); + coordf_t theta = ::acos(clamp(-1.0, 1.0, dot(new_dir, orig_dir))); if (cross(orig_dir, new_dir) < 0.0) theta = 2.0 * (coordf_t)PI - theta; // snap - if (length(m_center.vector_to(mouse_pos)) < 2.0 * (double)m_radius / 3.0) + double len = length(mouse_pos); + double in_radius = (double)m_radius / 3.0; + double out_radius = 2.0 * (double)in_radius; + if ((in_radius <= len) && (len <= out_radius)) { coordf_t step = 2.0 * (coordf_t)PI / (coordf_t)SnapRegionsCount; theta = step * (coordf_t)std::round(theta / step); @@ -250,7 +271,7 @@ void GLGizmoRotate::on_update(const Pointf& mouse_pos) if (theta == 2.0 * (coordf_t)PI) theta = 0.0; - m_angle_z = (float)theta; + m_angle = (float)theta; } void GLGizmoRotate::on_refresh() @@ -266,47 +287,83 @@ void GLGizmoRotate::on_render(const BoundingBoxf3& box) const { const Pointf3& size = box.size(); m_center = box.center(); +#if !ENABLE_GIZMOS_3D + m_center.z = 0.0; +#endif // !ENABLE_GIZMOS_3D + +#if ENABLE_GIZMOS_3D + m_radius = Offset + box.radius(); +#else m_radius = Offset + ::sqrt(sqr(0.5f * size.x) + sqr(0.5f * size.y)); +#endif // ENABLE_GIZMOS_3D m_keep_initial_values = true; } + ::glPushMatrix(); + transform_to_local(); + ::glLineWidth(2.0f); - ::glColor3fv(BaseColor); - _render_circle(); - _render_scale(); - _render_snap_radii(); - _render_reference_radius(); +#if ENABLE_GIZMOS_3D + ::glColor3fv((m_hover_id != -1) ? m_drag_color : m_base_color); +#else + ::glColor3fv(m_drag_color); +#endif // ENABLE_GIZMOS_3D - ::glColor3fv(HighlightColor); - _render_angle_z(); - _render_grabber(); + render_circle(); +#if ENABLE_GIZMOS_3D + if (m_hover_id != -1) + { +#endif // ENABLE_GIZMOS_3D + render_scale(); + render_snap_radii(); + render_reference_radius(); +#if ENABLE_GIZMOS_3D + } +#endif // ENABLE_GIZMOS_3D + + ::glColor3fv(m_highlight_color); +#if ENABLE_GIZMOS_3D + if (m_hover_id != -1) +#endif // ENABLE_GIZMOS_3D + render_angle(); + + render_grabber(); + + ::glPopMatrix(); } void GLGizmoRotate::on_render_for_picking(const BoundingBoxf3& box) const { ::glDisable(GL_DEPTH_TEST); + ::glPushMatrix(); + transform_to_local(); + m_grabbers[0].color[0] = 1.0f; m_grabbers[0].color[1] = 1.0f; - m_grabbers[0].color[2] = 254.0f / 255.0f; - render_grabbers(); + m_grabbers[0].color[2] = picking_color_component(0); + + render_grabbers_for_picking(); + + ::glPopMatrix(); } -void GLGizmoRotate::_render_circle() const +void GLGizmoRotate::render_circle() const { ::glBegin(GL_LINE_LOOP); for (unsigned int i = 0; i < ScaleStepsCount; ++i) { float angle = (float)i * ScaleStepRad; - float x = m_center.x + ::cos(angle) * m_radius; - float y = m_center.y + ::sin(angle) * m_radius; - ::glVertex3f((GLfloat)x, (GLfloat)y, 0.0f); + float x = ::cos(angle) * m_radius; + float y = ::sin(angle) * m_radius; + float z = 0.0f; + ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); } ::glEnd(); } -void GLGizmoRotate::_render_scale() const +void GLGizmoRotate::render_scale() const { float out_radius_long = m_radius + ScaleLongTooth; float out_radius_short = m_radius + ScaleShortTooth; @@ -317,17 +374,19 @@ void GLGizmoRotate::_render_scale() const float angle = (float)i * ScaleStepRad; float cosa = ::cos(angle); float sina = ::sin(angle); - float in_x = m_center.x + cosa * m_radius; - float in_y = m_center.y + sina * m_radius; - float out_x = (i % ScaleLongEvery == 0) ? m_center.x + cosa * out_radius_long : m_center.x + cosa * out_radius_short; - float out_y = (i % ScaleLongEvery == 0) ? m_center.y + sina * out_radius_long : m_center.y + sina * out_radius_short; - ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, 0.0f); - ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, 0.0f); + float in_x = cosa * m_radius; + float in_y = sina * m_radius; + float in_z = 0.0f; + float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; + float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; + float out_z = 0.0f; + ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); + ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); } ::glEnd(); } -void GLGizmoRotate::_render_snap_radii() const +void GLGizmoRotate::render_snap_radii() const { float step = 2.0f * (float)PI / (float)SnapRegionsCount; @@ -340,57 +399,306 @@ void GLGizmoRotate::_render_snap_radii() const float angle = (float)i * step; float cosa = ::cos(angle); float sina = ::sin(angle); - float in_x = m_center.x + cosa * in_radius; - float in_y = m_center.y + sina * in_radius; - float out_x = m_center.x + cosa * out_radius; - float out_y = m_center.y + sina * out_radius; - ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, 0.0f); - ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, 0.0f); + float in_x = cosa * in_radius; + float in_y = sina * in_radius; + float in_z = 0.0f; + float out_x = cosa * out_radius; + float out_y = sina * out_radius; + float out_z = 0.0f; + ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); + ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); } ::glEnd(); } -void GLGizmoRotate::_render_reference_radius() const +void GLGizmoRotate::render_reference_radius() const { ::glBegin(GL_LINES); - ::glVertex3f((GLfloat)m_center.x, (GLfloat)m_center.y, 0.0f); - ::glVertex3f((GLfloat)m_center.x + m_radius + GrabberOffset, (GLfloat)m_center.y, 0.0f); + ::glVertex3f(0.0f, 0.0f, 0.0f); + ::glVertex3f((GLfloat)(m_radius + GrabberOffset), 0.0f, 0.0f); ::glEnd(); } -void GLGizmoRotate::_render_angle_z() const +void GLGizmoRotate::render_angle() const { - float step_angle = m_angle_z / AngleResolution; + float step_angle = m_angle / AngleResolution; float ex_radius = m_radius + GrabberOffset; ::glBegin(GL_LINE_STRIP); for (unsigned int i = 0; i <= AngleResolution; ++i) { float angle = (float)i * step_angle; - float x = m_center.x + ::cos(angle) * ex_radius; - float y = m_center.y + ::sin(angle) * ex_radius; - ::glVertex3f((GLfloat)x, (GLfloat)y, 0.0f); + float x = ::cos(angle) * ex_radius; + float y = ::sin(angle) * ex_radius; + float z = 0.0f; + ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); } ::glEnd(); } -void GLGizmoRotate::_render_grabber() const +void GLGizmoRotate::render_grabber() const { float grabber_radius = m_radius + GrabberOffset; - m_grabbers[0].center.x = m_center.x + ::cos(m_angle_z) * grabber_radius; - m_grabbers[0].center.y = m_center.y + ::sin(m_angle_z) * grabber_radius; - m_grabbers[0].angle_z = m_angle_z; + m_grabbers[0].center.x = ::cos(m_angle) * grabber_radius; + m_grabbers[0].center.y = ::sin(m_angle) * grabber_radius; + m_grabbers[0].center.z = 0.0f; + m_grabbers[0].angle_z = m_angle; + +#if ENABLE_GIZMOS_3D + ::glColor3fv((m_hover_id != -1) ? m_drag_color : m_base_color); +#else + ::glColor3fv(m_drag_color); +#endif // ENABLE_GIZMOS_3D - ::glColor3fv(BaseColor); ::glBegin(GL_LINES); - ::glVertex3f((GLfloat)m_center.x, (GLfloat)m_center.y, 0.0f); - ::glVertex3f((GLfloat)m_grabbers[0].center.x, (GLfloat)m_grabbers[0].center.y, 0.0f); + ::glVertex3f(0.0f, 0.0f, 0.0f); + ::glVertex3f((GLfloat)m_grabbers[0].center.x, (GLfloat)m_grabbers[0].center.y, (GLfloat)m_grabbers[0].center.z); ::glEnd(); - ::memcpy((void*)m_grabbers[0].color, (const void*)HighlightColor, 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float)); render_grabbers(); } +void GLGizmoRotate::transform_to_local() const +{ + ::glTranslatef((GLfloat)m_center.x, (GLfloat)m_center.y, (GLfloat)m_center.z); + + switch (m_axis) + { + case X: + { + ::glRotatef(90.0f, 0.0f, 1.0f, 0.0f); + ::glRotatef(90.0f, 0.0f, 0.0f, 1.0f); + break; + } + case Y: + { + ::glRotatef(90.0f, 1.0f, 0.0f, 0.0f); + ::glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + break; + } + default: + case Z: + { + // no rotation + break; + } + } +} + +Pointf GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) const +{ + Eigen::Transform m = Eigen::Transform::Identity(); + + switch (m_axis) + { + case X: + { + m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitZ())); + m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitY())); + break; + } + case Y: + { + m.rotate(Eigen::AngleAxisf(-(float)PI, Eigen::Vector3f::UnitZ())); + m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitX())); + break; + } + default: + case Z: + { + // no rotation applied + break; + } + } + + m.translate(Eigen::Vector3f((float)-m_center.x, (float)-m_center.y, (float)-m_center.z)); + + Eigen::Matrix world_ray; + Eigen::Matrix local_ray; + world_ray(0, 0) = (float)mouse_ray.a.x; + world_ray(1, 0) = (float)mouse_ray.a.y; + world_ray(2, 0) = (float)mouse_ray.a.z; + world_ray(0, 1) = (float)mouse_ray.b.x; + world_ray(1, 1) = (float)mouse_ray.b.y; + world_ray(2, 1) = (float)mouse_ray.b.z; + local_ray = m * world_ray.colwise().homogeneous(); + + return Linef3(Pointf3(local_ray(0, 0), local_ray(1, 0), local_ray(2, 0)), Pointf3(local_ray(0, 1), local_ray(1, 1), local_ray(2, 1))).intersect_plane(0.0); +} + +GLGizmoRotate3D::GLGizmoRotate3D() + : GLGizmoBase() + , m_x(GLGizmoRotate::X) + , m_y(GLGizmoRotate::Y) + , m_z(GLGizmoRotate::Z) +{ + m_is_container = true; + + m_x.set_group_id(0); + m_y.set_group_id(1); + m_z.set_group_id(2); +} + +float GLGizmoRotate3D::get_angle_x() const +{ + return m_x.get_angle(); +} + +void GLGizmoRotate3D::set_angle_x(float angle) +{ + m_x.set_angle(angle); +} + +float GLGizmoRotate3D::get_angle_y() const +{ + return m_y.get_angle(); +} + +void GLGizmoRotate3D::set_angle_y(float angle) +{ + m_y.set_angle(angle); +} + +float GLGizmoRotate3D::get_angle_z() const +{ + return m_z.get_angle(); +} + +void GLGizmoRotate3D::set_angle_z(float angle) +{ + m_z.set_angle(angle); +} + +bool GLGizmoRotate3D::on_init() +{ + if (!m_x.init() || !m_y.init() || !m_z.init()) + return false; + + float red[3] = { 1.0f, 0.0f, 0.0f }; + float green[3] = { 0.0f, 1.0f, 0.0f }; + float blue[3] = { 0.0f, 0.0f, 1.0f }; + + m_x.set_highlight_color(red); + m_y.set_highlight_color(green); + m_z.set_highlight_color(blue); + + std::string path = resources_dir() + "/icons/overlay/"; + + std::string filename = path + "rotate_off.png"; + if (!m_textures[Off].load_from_file(filename, false)) + return false; + + filename = path + "rotate_hover.png"; + if (!m_textures[Hover].load_from_file(filename, false)) + return false; + + filename = path + "rotate_on.png"; + if (!m_textures[On].load_from_file(filename, false)) + return false; + + return true; +} + +void GLGizmoRotate3D::on_set_state() +{ + m_x.set_state(m_state); + m_y.set_state(m_state); + m_z.set_state(m_state); +} + +void GLGizmoRotate3D::on_set_hover_id() +{ + m_x.set_hover_id(m_hover_id == 0 ? 0 : -1); + m_y.set_hover_id(m_hover_id == 1 ? 0 : -1); + m_z.set_hover_id(m_hover_id == 2 ? 0 : -1); +} + +void GLGizmoRotate3D::on_start_dragging() +{ + switch (m_hover_id) + { + case 0: + { + m_x.start_dragging(); + break; + } + case 1: + { + m_y.start_dragging(); + break; + } + case 2: + { + m_z.start_dragging(); + break; + } + default: + { + break; + } + } +} + +void GLGizmoRotate3D::on_stop_dragging() +{ + switch (m_hover_id) + { + case 0: + { + m_x.stop_dragging(); + break; + } + case 1: + { + m_y.stop_dragging(); + break; + } + case 2: + { + m_z.stop_dragging(); + break; + } + default: + { + break; + } + } +} + +void GLGizmoRotate3D::on_update(const Linef3& mouse_ray) +{ + m_x.update(mouse_ray); + m_y.update(mouse_ray); + m_z.update(mouse_ray); +} + +void GLGizmoRotate3D::on_refresh() +{ + m_x.refresh(); + m_y.refresh(); + m_z.refresh(); +} + +void GLGizmoRotate3D::on_render(const BoundingBoxf3& box) const +{ + if ((m_hover_id == -1) || (m_hover_id == 0)) + m_x.render(box); + + if ((m_hover_id == -1) || (m_hover_id == 1)) + m_y.render(box); + + if ((m_hover_id == -1) || (m_hover_id == 2)) + m_z.render(box); +} + +void GLGizmoRotate3D::on_render_for_picking(const BoundingBoxf3& box) const +{ + m_x.render_for_picking(box); + m_y.render_for_picking(box); + m_z.render_for_picking(box); +} + const float GLGizmoScale::Offset = 5.0f; GLGizmoScale::GLGizmoScale() @@ -440,8 +748,9 @@ void GLGizmoScale::on_start_dragging() m_starting_drag_position = m_grabbers[m_hover_id].center; } -void GLGizmoScale::on_update(const Pointf& mouse_pos) +void GLGizmoScale::on_update(const Linef3& mouse_ray) { + Pointf mouse_pos = mouse_ray.intersect_plane(0.0); Pointf center(0.5 * (m_grabbers[1].center.x + m_grabbers[0].center.x), 0.5 * (m_grabbers[3].center.y + m_grabbers[0].center.y)); coordf_t orig_len = length(m_starting_drag_position - center); @@ -470,7 +779,8 @@ void GLGizmoScale::on_render(const BoundingBoxf3& box) const m_grabbers[3].center.y = max_y; ::glLineWidth(2.0f); - ::glColor3fv(BaseColor); + ::glColor3fv(m_drag_color); + // draw outline ::glBegin(GL_LINE_LOOP); for (unsigned int i = 0; i < 4; ++i) @@ -482,24 +792,22 @@ void GLGizmoScale::on_render(const BoundingBoxf3& box) const // draw grabbers for (unsigned int i = 0; i < 4; ++i) { - ::memcpy((void*)m_grabbers[i].color, (const void*)HighlightColor, 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 3 * sizeof(float)); } render_grabbers(); } void GLGizmoScale::on_render_for_picking(const BoundingBoxf3& box) const { - static const GLfloat INV_255 = 1.0f / 255.0f; - ::glDisable(GL_DEPTH_TEST); for (unsigned int i = 0; i < 4; ++i) { m_grabbers[i].color[0] = 1.0f; m_grabbers[i].color[1] = 1.0f; - m_grabbers[i].color[2] = (254.0f - (float)i) * INV_255; + m_grabbers[i].color[2] = picking_color_component(i); } - render_grabbers(); + render_grabbers_for_picking(); } } // namespace GUI diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp index 839969090..fafd8091a 100644 --- a/xs/src/slic3r/GUI/GLGizmo.hpp +++ b/xs/src/slic3r/GUI/GLGizmo.hpp @@ -6,30 +6,38 @@ #include +#define ENABLE_GIZMOS_3D 1 + namespace Slic3r { class BoundingBoxf3; class Pointf3; +class Linef3; namespace GUI { class GLGizmoBase { protected: - static const float BaseColor[3]; - static const float HighlightColor[3]; - struct Grabber { static const float HalfSize; - static const float HoverOffset; + static const float DraggingScaleFactor; - Pointf center; + Pointf3 center; + float angle_x; + float angle_y; float angle_z; float color[3]; + bool dragging; Grabber(); + void render(bool hover) const; + void render_for_picking() const; + + private: + void render(const float* render_color) const; }; public: @@ -42,30 +50,40 @@ public: }; protected: + int m_group_id; EState m_state; // textures are assumed to be square and all with the same size in pixels, no internal check is done GLTexture m_textures[Num_States]; int m_hover_id; + float m_base_color[3]; + float m_drag_color[3]; + float m_highlight_color[3]; mutable std::vector m_grabbers; + bool m_is_container; public: GLGizmoBase(); - virtual ~GLGizmoBase(); + virtual ~GLGizmoBase() {} - bool init(); + bool init() { return on_init(); } - EState get_state() const; - void set_state(EState state); + int get_group_id() const { return m_group_id; } + void set_group_id(int id) { m_group_id = id; } + + EState get_state() const { return m_state; } + void set_state(EState state) { m_state = state; on_set_state(); } unsigned int get_texture_id() const; int get_textures_size() const; - int get_hover_id() const; + int get_hover_id() const { return m_hover_id; } void set_hover_id(int id); + void set_highlight_color(const float* color); + void start_dragging(); void stop_dragging(); - void update(const Pointf& mouse_pos); + void update(const Linef3& mouse_ray); void refresh(); void render(const BoundingBoxf3& box) const; @@ -73,15 +91,18 @@ public: protected: virtual bool on_init() = 0; - virtual void on_set_state(); - virtual void on_start_dragging(); - virtual void on_stop_dragging(); - virtual void on_update(const Pointf& mouse_pos) = 0; - virtual void on_refresh(); + virtual void on_set_state() {} + virtual void on_set_hover_id() {} + virtual void on_start_dragging() {} + virtual void on_stop_dragging() {} + virtual void on_update(const Linef3& mouse_ray) = 0; + virtual void on_refresh() {} virtual void on_render(const BoundingBoxf3& box) const = 0; virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0; + float picking_color_component(unsigned int id) const; void render_grabbers() const; + void render_grabbers_for_picking() const; }; class GLGizmoRotate : public GLGizmoBase @@ -97,33 +118,76 @@ class GLGizmoRotate : public GLGizmoBase static const unsigned int SnapRegionsCount; static const float GrabberOffset; - float m_angle_z; +public: + enum Axis : unsigned char + { + X, + Y, + Z + }; - mutable Pointf m_center; +private: + Axis m_axis; + float m_angle; + + mutable Pointf3 m_center; mutable float m_radius; mutable bool m_keep_initial_values; public: - GLGizmoRotate(); + explicit GLGizmoRotate(Axis axis); - float get_angle_z() const; - void set_angle_z(float angle_z); + float get_angle() const; + void set_angle(float angle); protected: virtual bool on_init(); virtual void on_set_state(); - virtual void on_update(const Pointf& mouse_pos); + virtual void on_update(const Linef3& mouse_ray); virtual void on_refresh(); virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const; private: - void _render_circle() const; - void _render_scale() const; - void _render_snap_radii() const; - void _render_reference_radius() const; - void _render_angle_z() const; - void _render_grabber() const; + void render_circle() const; + void render_scale() const; + void render_snap_radii() const; + void render_reference_radius() const; + void render_angle() const; + void render_grabber() const; + + void transform_to_local() const; + Pointf mouse_position_in_local_plane(const Linef3& mouse_ray) const; +}; + +class GLGizmoRotate3D : public GLGizmoBase +{ + GLGizmoRotate m_x; + GLGizmoRotate m_y; + GLGizmoRotate m_z; + +public: + GLGizmoRotate3D(); + + float get_angle_x() const; + void set_angle_x(float angle); + + float get_angle_y() const; + void set_angle_y(float angle); + + float get_angle_z() const; + void set_angle_z(float angle); + +protected: + virtual bool on_init(); + virtual void on_set_state(); + virtual void on_set_hover_id(); + virtual void on_start_dragging(); + virtual void on_stop_dragging(); + virtual void on_update(const Linef3& mouse_ray); + virtual void on_refresh(); + virtual void on_render(const BoundingBoxf3& box) const; + virtual void on_render_for_picking(const BoundingBoxf3& box) const; }; class GLGizmoScale : public GLGizmoBase @@ -144,7 +208,7 @@ public: protected: virtual bool on_init(); virtual void on_start_dragging(); - virtual void on_update(const Pointf& mouse_pos); + virtual void on_update(const Linef3& mouse_ray); virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const; };