diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index a2c59ec17d..d1c1a03e0d 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -326,40 +326,36 @@ Vec3d extract_euler_angles(const Eigen::Matrix& Vec3d angles1 = Vec3d::Zero(); Vec3d angles2 = Vec3d::Zero(); // BBS: rotation_matrix(2, 0) may be slighterly larger than 1 due to numerical accuracy - if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1) - { - angles1(2) = 0.0; - if (rotation_matrix(2, 0) < 0.0) // == -1.0 - { - angles1(1) = 0.5 * (double)PI; - angles1(0) = angles1(2) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); + if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1) { + angles1.z() = 0.0; + if (rotation_matrix(2, 0) < 0.0) { // == -1.0 + angles1.y() = 0.5 * double(PI); + angles1.x() = angles1.z() + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); } - else // == 1.0 - { - angles1(1) = - 0.5 * (double)PI; - angles1(0) = - angles1(2) + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2)); + else { // == 1.0 + angles1.y() = - 0.5 * double(PI); + angles1.x() = - angles1.y() + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2)); } angles2 = angles1; } - else - { - angles1(1) = -::asin(rotation_matrix(2, 0)); - double inv_cos1 = 1.0 / ::cos(angles1(1)); - angles1(0) = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1); - angles1(2) = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1); + else { + angles1.y() = -::asin(rotation_matrix(2, 0)); + const double inv_cos1 = 1.0 / ::cos(angles1.y()); + angles1.x() = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1); + angles1.z() = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1); - angles2(1) = (double)PI - angles1(1); - double inv_cos2 = 1.0 / ::cos(angles2(1)); - angles2(0) = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2); - angles2(2) = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2); + angles2.y() = double(PI) - angles1.y(); + const double inv_cos2 = 1.0 / ::cos(angles2.y()); + angles2.x() = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2); + angles2.z() = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2); } // The following euristic is the best found up to now (in the sense that it works fine with the greatest number of edge use-cases) // but there are other use-cases were it does not // We need to improve it - double min_1 = angles1.cwiseAbs().minCoeff(); - double min_2 = angles2.cwiseAbs().minCoeff(); - bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm())); + const double min_1 = angles1.cwiseAbs().minCoeff(); + const double min_2 = angles2.cwiseAbs().minCoeff(); + const bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm())); return use_1 ? angles1 : angles2; } @@ -423,14 +419,6 @@ Transform3d rotation_transform(const Vec3d& rotation) return transform; } -Transformation::Flags::Flags() - : dont_translate(true) - , dont_rotate(true) - , dont_scale(true) - , dont_mirror(true) -{ -} - bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror); @@ -456,15 +444,14 @@ Transformation::Transformation(const Transform3d& transform) void Transformation::set_offset(const Vec3d& offset) { - set_offset(X, offset(0)); - set_offset(Y, offset(1)); - set_offset(Z, offset(2)); + set_offset(X, offset.x()); + set_offset(Y, offset.y()); + set_offset(Z, offset.z()); } void Transformation::set_offset(Axis axis, double offset) { - if (m_offset(axis) != offset) - { + if (m_offset(axis) != offset) { m_offset(axis) = offset; m_dirty = true; } @@ -472,19 +459,18 @@ void Transformation::set_offset(Axis axis, double offset) void Transformation::set_rotation(const Vec3d& rotation) { - set_rotation(X, rotation(0)); - set_rotation(Y, rotation(1)); - set_rotation(Z, rotation(2)); + set_rotation(X, rotation.x()); + set_rotation(Y, rotation.y()); + set_rotation(Z, rotation.z()); } void Transformation::set_rotation(Axis axis, double rotation) { rotation = angle_to_0_2PI(rotation); - if (is_approx(std::abs(rotation), 2.0 * (double)PI)) + if (is_approx(std::abs(rotation), 2.0 * double(PI))) rotation = 0.0; - if (m_rotation(axis) != rotation) - { + if (m_rotation(axis) != rotation) { m_rotation(axis) = rotation; m_dirty = true; } @@ -492,15 +478,14 @@ void Transformation::set_rotation(Axis axis, double rotation) void Transformation::set_scaling_factor(const Vec3d& scaling_factor) { - set_scaling_factor(X, scaling_factor(0)); - set_scaling_factor(Y, scaling_factor(1)); - set_scaling_factor(Z, scaling_factor(2)); + set_scaling_factor(X, scaling_factor.x()); + set_scaling_factor(Y, scaling_factor.y()); + set_scaling_factor(Z, scaling_factor.z()); } void Transformation::set_scaling_factor(Axis axis, double scaling_factor) { - if (m_scaling_factor(axis) != std::abs(scaling_factor)) - { + if (m_scaling_factor(axis) != std::abs(scaling_factor)) { m_scaling_factor(axis) = std::abs(scaling_factor); m_dirty = true; } @@ -508,9 +493,9 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor) void Transformation::set_mirror(const Vec3d& mirror) { - set_mirror(X, mirror(0)); - set_mirror(Y, mirror(1)); - set_mirror(Z, mirror(2)); + set_mirror(X, mirror.x()); + set_mirror(Y, mirror.y()); + set_mirror(Z, mirror.z()); } void Transformation::set_mirror(Axis axis, double mirror) @@ -521,8 +506,7 @@ void Transformation::set_mirror(Axis axis, double mirror) else if (abs_mirror != 1.0) mirror /= abs_mirror; - if (m_mirror(axis) != mirror) - { + if (m_mirror(axis) != mirror) { m_mirror(axis) = mirror; m_dirty = true; } @@ -540,9 +524,8 @@ void Transformation::set_from_transform(const Transform3d& transform) // we can only detect if the matrix contains a left handed reference system // in which case we reorient it back to right handed by mirroring the x axis Vec3d mirror = Vec3d::Ones(); - if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) - { - mirror(0) = -1.0; + if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) { + mirror.x() = -1.0; // remove mirror m3x3.col(0) *= -1.0; } @@ -579,8 +562,7 @@ void Transformation::reset() const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { - if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) - { + if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) { m_matrix = Geometry::assemble_transform( dont_translate ? Vec3d::Zero() : m_offset, dont_rotate ? Vec3d::Zero() : m_rotation, @@ -609,8 +591,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation // Just set the inverse. out.set_from_transform(instance_transformation.get_matrix(true).inverse()); } - else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) - { + else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) { // Anisotropic scaling, rotation by multiples of ninety degrees. Eigen::Matrix3d instance_rotation_trafo = (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * @@ -643,8 +624,8 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); - out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); - out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); + out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z()))); + out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1)); } else { @@ -663,19 +644,15 @@ Transform3d transform3d_from_string(const std::string& transform_str) assert(is_decimal_separator_point()); // for atof Transform3d transform = Transform3d::Identity(); - if (!transform_str.empty()) - { + if (!transform_str.empty()) { std::vector mat_elements_str; boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on); - unsigned int size = (unsigned int)mat_elements_str.size(); - if (size == 16) - { + const unsigned int size = (unsigned int)mat_elements_str.size(); + if (size == 16) { unsigned int i = 0; - for (unsigned int r = 0; r < 4; ++r) - { - for (unsigned int c = 0; c < 4; ++c) - { + for (unsigned int r = 0; r < 4; ++r) { + for (unsigned int c = 0; c < 4; ++c) { transform(r, c) = ::atof(mat_elements_str[i++].c_str()); } } @@ -689,17 +666,17 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot { return // From the current coordinate system to world. - Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * + Eigen::AngleAxisd(rot_xyz_to.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to.x(), Vec3d::UnitX()) * // From world to the initial coordinate system. - Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); + Eigen::AngleAxisd(-rot_xyz_from.x(), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from.z(), Vec3d::UnitZ()); } // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) { - Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); - Vec3d axis = angle_axis.axis(); - double angle = angle_axis.angle(); + const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); + const Vec3d axis = angle_axis.axis(); + const double angle = angle_axis.angle(); #ifndef NDEBUG if (std::abs(angle) > 1e-8) { assert(std::abs(axis.x()) < 1e-8); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 8eb6195a10..cbb5df6a81 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -361,25 +361,23 @@ class Transformation { struct Flags { - bool dont_translate; - bool dont_rotate; - bool dont_scale; - bool dont_mirror; - - Flags(); + bool dont_translate{ true }; + bool dont_rotate{ true }; + bool dont_scale{ true }; + bool dont_mirror{ true }; bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const; void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror); }; - Vec3d m_offset; // In unscaled coordinates - Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point - Vec3d m_scaling_factor; // Scaling factors along the three axes - Vec3d m_mirror; // Mirroring along the three axes + Vec3d m_offset{ Vec3d::Zero() }; // In unscaled coordinates + Vec3d m_rotation{ Vec3d::Zero() }; // Rotation around the three axes, in radians around mesh center point + Vec3d m_scaling_factor{ Vec3d::Ones() }; // Scaling factors along the three axes + Vec3d m_mirror{ Vec3d::Ones() }; // Mirroring along the three axes - mutable Transform3d m_matrix; + mutable Transform3d m_matrix{ Transform3d::Identity() }; mutable Flags m_flags; - mutable bool m_dirty; + mutable bool m_dirty{ false }; public: Transformation(); @@ -457,7 +455,7 @@ extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to // Is the angle close to a multiple of 90 degrees? inline bool is_rotation_ninety_degrees(double a) { - a = fmod(std::abs(a), 0.5 * M_PI); + a = fmod(std::abs(a), 0.5 * PI); if (a > 0.25 * PI) a = 0.5 * PI - a; return a < 0.001; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1405688521..54846f168d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -462,19 +462,62 @@ void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) const float scale_y = bar_rect.get_height() / m_object_max_z; const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; - // Baseline - glsafe(::glColor3f(0.0f, 0.0f, 0.0f)); - ::glBegin(GL_LINE_STRIP); - ::glVertex2f(x, bar_rect.get_bottom()); - ::glVertex2f(x, bar_rect.get_top()); - glsafe(::glEnd()); + bool bar_rect_changed = m_profile.old_bar_rect != bar_rect; + m_profile.old_bar_rect = bar_rect; - // Curve - glsafe(::glColor3f(0.0f, 0.0f, 1.0f)); - ::glBegin(GL_LINE_STRIP); - for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2) - ::glVertex2f(bar_rect.get_left() + (float)m_layer_height_profile[i + 1] * scale_x, bar_rect.get_bottom() + (float)m_layer_height_profile[i] * scale_y); - glsafe(::glEnd()); + // Baseline + if (!m_profile.baseline.is_initialized() || bar_rect_changed) { + m_profile.old_bar_rect = bar_rect; + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(x, bar_rect.get_bottom(), 0.0f); + entity.positions.emplace_back(x, bar_rect.get_top(), 0.0f); + + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_profile.baseline.init_from(init_data); + m_profile.baseline.set_color(-1, ColorRGBA::BLACK()); + } + + if (!m_profile.profile.is_initialized() || bar_rect_changed || m_profile.old_layer_height_profile != m_layer_height_profile) { + m_profile.old_layer_height_profile = m_layer_height_profile; + m_profile.profile.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineStrip; + entity.positions.reserve(m_layer_height_profile.size()); + entity.normals.reserve(m_layer_height_profile.size()); + entity.indices.reserve(m_layer_height_profile.size()); + for (unsigned int i = 0; i < unsigned int(m_layer_height_profile.size()); i += 2) { + entity.positions.emplace_back(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i / 2); + } + + init_data.entities.emplace_back(entity); + m_profile.profile.init_from(init_data); + m_profile.profile.set_color(-1, ColorRGBA::BLUE()); + } + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + m_profile.baseline.render(); + m_profile.profile.render(); + shader->stop_using(); + } } void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const GLVolumeCollection & volumes)//render volume and layer height texture (has mapping relation with each other) @@ -6822,7 +6865,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with default: case GLVolumeCollection::ERenderType::Opaque: { - const GLGizmosManager& gm = get_gizmos_manager(); + GLGizmosManager& gm = get_gizmos_manager(); if (dynamic_cast(gm.get_current()) == nullptr) { if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) { @@ -8070,28 +8113,59 @@ void GLCanvas3D::_render_assemble_info() const } #if ENABLE_SHOW_CAMERA_TARGET -void GLCanvas3D::_render_camera_target() const +void GLCanvas3D::_render_camera_target() { - double half_length = 5.0; + static const double half_length = 5.0; glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glLineWidth(2.0f)); - ::glBegin(GL_LINES); const Vec3d& target = wxGetApp().plater()->get_camera().get_target(); - // draw line for x axis - ::glColor3f(1.0f, 0.0f, 0.0f); - ::glVertex3d(target(0) - half_length, target(1), target(2)); - ::glVertex3d(target(0) + half_length, target(1), target(2)); - // draw line for y axis - ::glColor3f(0.0f, 1.0f, 0.0f); - ::glVertex3d(target(0), target(1) - half_length, target(2)); - ::glVertex3d(target(0), target(1) + half_length, target(2)); - // draw line for z axis - ::glColor3f(0.0f, 0.0f, 1.0f); - ::glVertex3d(target(0), target(1), target(2) - half_length); - ::glVertex3d(target(0), target(1), target(2) + half_length); - glsafe(::glEnd()); + bool target_changed = !m_camera_target.target.isApprox(target); + m_camera_target.target = target; + + for (int i = 0; i < 3; ++i) { + if (!m_camera_target.axis[i].is_initialized() || target_changed) { + m_camera_target.axis[i].reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + if (i == X) { + entity.positions.emplace_back(target.x() - half_length, target.y(), target.z()); + entity.positions.emplace_back(target.x() + half_length, target.y(), target.z()); + } + else if (i == Y) { + entity.positions.emplace_back(target.x(), target.y() - half_length, target.z()); + entity.positions.emplace_back(target.x(), target.y() + half_length, target.z()); + } + else { + entity.positions.emplace_back(target.x(), target.y(), target.z() - half_length); + entity.positions.emplace_back(target.x(), target.y(), target.z() + half_length); + } + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_camera_target.axis[i].init_from(init_data); + m_camera_target.axis[i].set_color(-1, (i == X) ? ColorRGBA::X() : (i == Y) ? ColorRGBA::Y() : ColorRGBA::Z()); + } + } + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + for (int i = 0; i < 3; ++i) { + m_camera_target.axis[i].render(); + } + shader->stop_using(); + } } #endif // ENABLE_SHOW_CAMERA_TARGET diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index a7d4017973..ceb9eacc76 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -257,6 +257,14 @@ class GLCanvas3D int last_object_id{ -1 }; float last_z{ 0.0f }; LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE }; + struct Profile + { + GLModel baseline; + GLModel profile; + Rect old_bar_rect; + std::vector old_layer_height_profile; + }; + Profile m_profile; LayersEditing() = default; ~LayersEditing(); @@ -698,6 +706,15 @@ public: } m_gizmo_highlighter; +#if ENABLE_SHOW_CAMERA_TARGET + struct CameraTarget + { + std::array axis; + Vec3d target{ Vec3d::Zero() }; + }; + + CameraTarget m_camera_target; +#endif // ENABLE_SHOW_CAMERA_TARGET public: explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed); ~GLCanvas3D(); @@ -1139,7 +1156,7 @@ private: void _render_assemble_control() const; void _render_assemble_info() const; #if ENABLE_SHOW_CAMERA_TARGET - void _render_camera_target() const; + void _render_camera_target(); #endif // ENABLE_SHOW_CAMERA_TARGET void _render_sla_slices(); void _render_selection_sidebar_hints(); diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index f6dfbe10f7..30b7888c53 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -69,7 +69,7 @@ namespace GUI { m_state = Off; } - void GLSelectionRectangle::render(const GLCanvas3D& canvas) const + void GLSelectionRectangle::render(const GLCanvas3D& canvas) { if (!is_dragging()) return; @@ -92,11 +92,6 @@ namespace GUI { float bottom = (float)std::min(start(1), end(1)) * inv_zoom; glsafe(::glLineWidth(1.5f)); - float color[3]; - color[0] = 0.00f; - color[1] = 1.00f; - color[2] = 0.38f; - glsafe(::glColor3fv(color)); glsafe(::glDisable(GL_DEPTH_TEST)); @@ -112,12 +107,46 @@ namespace GUI { glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - ::glBegin(GL_LINE_LOOP); - ::glVertex2f((GLfloat)left, (GLfloat)bottom); - ::glVertex2f((GLfloat)right, (GLfloat)bottom); - ::glVertex2f((GLfloat)right, (GLfloat)top); - ::glVertex2f((GLfloat)left, (GLfloat)top); - glsafe(::glEnd()); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + if (!m_rectangle.is_initialized() || !m_old_start_corner.isApprox(m_start_corner) || !m_old_end_corner.isApprox(m_end_corner)) { + m_old_start_corner = m_start_corner; + m_old_end_corner = m_end_corner; + m_rectangle.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineLoop; + entity.positions.reserve(4); + entity.positions.emplace_back(left, bottom, 0.0f); + entity.positions.emplace_back(right, bottom, 0.0f); + entity.positions.emplace_back(right, top, 0.0f); + entity.positions.emplace_back(left, top, 0.0f); + + entity.normals.reserve(4); + for (size_t j = 0; j < 5; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(6); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + entity.indices.emplace_back(2); + entity.indices.emplace_back(2); + entity.indices.emplace_back(3); + entity.indices.emplace_back(0); + + init_data.entities.emplace_back(entity); + m_rectangle.init_from(init_data); + } + + ColorRGBA color(0.0f, 1.0f, 0.38f, 1.0f); + m_rectangle.set_color(-1, color); + m_rectangle.render(); + shader->stop_using(); + } glsafe(::glPopAttrib()); diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index d9869771ef..ad0360e0cc 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -2,6 +2,7 @@ #define slic3r_GLSelectionRectangle_hpp_ #include "libslic3r/Point.hpp" +#include "GLModel.hpp" namespace Slic3r { namespace GUI { @@ -30,7 +31,7 @@ public: // Disables the rectangle. void stop_dragging(); - void render(const GLCanvas3D& canvas) const; + void render(const GLCanvas3D& canvas); bool is_dragging() const { return m_state != Off; } EState get_state() const { return m_state; } @@ -43,9 +44,12 @@ public: float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); } private: - EState m_state = Off; - Vec2d m_start_corner; - Vec2d m_end_corner; + EState m_state{ Off }; + Vec2d m_start_corner{ Vec2d::Zero() }; + Vec2d m_end_corner{ Vec2d::Zero() }; + GLModel m_rectangle; + Vec2d m_old_start_corner{ Vec2d::Zero() }; + Vec2d m_old_end_corner{ Vec2d::Zero() }; }; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index c5c3558ebb..6b39c44f58 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -33,7 +33,8 @@ std::pair GLShadersManager::init() bool valid = true; - // basic shader, used to render selection bbox + // basic shader, used to render selection bbox, gizmo cut plane and grabbers connections, + // gizmo move grabbers connections, gizmo scale grabbers connections valid &= append_shader("flat", { "flat.vs", "flat.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 49622d84c5..b9dc5770d4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -105,7 +105,7 @@ bool GLGizmoFdmSupports::on_init() return true; } -void GLGizmoFdmSupports::render_painter_gizmo() const +void GLGizmoFdmSupports::render_painter_gizmo() { const Selection& selection = m_parent.get_selection(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 6960a81dc6..23e782fa1c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -15,7 +15,7 @@ class GLGizmoFdmSupports : public GLGizmoPainterBase public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - void render_painter_gizmo() const override; + void render_painter_gizmo() override; //BBS: add edit state enum EditState { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 3dbb020fe6..30bc71f8e6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -146,7 +146,7 @@ GLGizmoMmuSegmentation::GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::st { } -void GLGizmoMmuSegmentation::render_painter_gizmo() const +void GLGizmoMmuSegmentation::render_painter_gizmo() { const Selection& selection = m_parent.get_selection(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index e7ec8d7bc2..7457d97101 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -67,7 +67,7 @@ public: GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); ~GLGizmoMmuSegmentation() override = default; - void render_painter_gizmo() const override; + void render_painter_gizmo() override; void set_painter_gizmo_data(const Selection& selection) override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 62fc1dc6ff..483c833d74 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -23,11 +23,6 @@ const double GLGizmoMove3D::Offset = 10.0; //BBS: GUI refactor: add obj manipulation GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) : GLGizmoBase(parent, icon_filename, sprite_id) - , m_displacement(Vec3d::Zero()) - , m_snap_step(1.0) - , m_starting_drag_position(Vec3d::Zero()) - , m_starting_box_center(Vec3d::Zero()) - , m_starting_box_bottom_center(Vec3d::Zero()) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) { @@ -137,25 +132,57 @@ void GLGizmoMove3D::on_render() glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - // draw grabbers - for (unsigned int i = 0; i < 3; ++i) { - if (m_grabbers[i].enabled) render_grabber_extension((Axis) i, box, false); - } + auto render_grabber_connection = [this, ¢er](unsigned int id) { + if (m_grabbers[id].enabled) { + if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) { + m_grabber_connections[id].old_center = center; + m_grabber_connections[id].model.reset(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(center.cast()); + entity.positions.emplace_back(m_grabbers[id].center.cast()); + + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_grabber_connections[id].model.init_from(init_data); + m_grabber_connections[id].model.set_color(-1, AXES_COLOR[id]); + } - // draw axes line - // draw axes - for (unsigned int i = 0; i < 3; ++i) { - if (m_grabbers[i].enabled) { - glsafe(::glColor4fv(AXES_COLOR[i].data())); glLineStipple(1, 0x0FFF); glEnable(GL_LINE_STIPPLE); - ::glBegin(GL_LINES); - ::glVertex3dv(center.data()); - // use extension center - ::glVertex3dv(m_grabbers[i].center.data()); - glsafe(::glEnd()); + m_grabber_connections[id].model.render(); glDisable(GL_LINE_STIPPLE); } + }; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + // draw axes line + // draw axes + for (unsigned int i = 0; i < 3; ++i) { + render_grabber_connection(i); + } + + shader->stop_using(); + } + + // draw grabbers + for (unsigned int i = 0; i < 3; ++i) { + if (m_grabbers[i].enabled) + render_grabber_extension((Axis) i, box, false); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 21d19b4465..70ae525f78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -15,15 +15,19 @@ class GLGizmoMove3D : public GLGizmoBase { static const double Offset; - Vec3d m_displacement; - - double m_snap_step; - - Vec3d m_starting_drag_position; - Vec3d m_starting_box_center; - Vec3d m_starting_box_bottom_center; + Vec3d m_displacement{ Vec3d::Zero() }; + double m_snap_step{ 1.0 }; + Vec3d m_starting_drag_position{ Vec3d::Zero() }; + Vec3d m_starting_box_center{ Vec3d::Zero() }; + Vec3d m_starting_box_bottom_center{ Vec3d::Zero() }; GLModel m_vbo_cone; + struct GrabberConnection + { + GLModel model; + Vec3d old_center{ Vec3d::Zero() }; + }; + std::array m_grabber_connections; //BBS: add size adjust related GizmoObjectManipulation* m_object_manipulation; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 7e68b73730..53fc03edcb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -119,7 +119,7 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const } -void GLGizmoPainterBase::render_cursor() const +void GLGizmoPainterBase::render_cursor() { // First check that the mouse pointer is on an object. const ModelObject* mo = m_c->selection_info()->model_object(); @@ -159,31 +159,22 @@ void GLGizmoPainterBase::render_cursor() const -void GLGizmoPainterBase::render_cursor_circle() const +void GLGizmoPainterBase::render_cursor_circle() { const Camera &camera = wxGetApp().plater()->get_camera(); - auto zoom = (float) camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + const float zoom = float(camera.get_zoom()); + const float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - Size cnv_size = m_parent.get_canvas_size(); - float cnv_half_width = 0.5f * (float) cnv_size.get_width(); - float cnv_half_height = 0.5f * (float) cnv_size.get_height(); - if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) + const Size cnv_size = m_parent.get_canvas_size(); + const float cnv_half_width = 0.5f * float(cnv_size.get_width()); + const float cnv_half_height = 0.5f * float(cnv_size.get_height()); + if (cnv_half_width == 0.0f || cnv_half_height == 0.0f) return; - Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); - Vec2d center(mouse_pos(0) - cnv_half_width, cnv_half_height - mouse_pos(1)); + const Vec2d mouse_pos(m_parent.get_local_mouse_position().x(), m_parent.get_local_mouse_position().y()); + Vec2d center(mouse_pos.x() - cnv_half_width, cnv_half_height - mouse_pos.y()); center = center * inv_zoom; glsafe(::glLineWidth(1.5f)); - - // BBS - ColorRGBA render_color = this->get_cursor_hover_color(); - if (m_button_down == Button::Left) - render_color = this->get_cursor_sphere_left_button_color(); - else if (m_button_down == Button::Right) - render_color = this->get_cursor_sphere_right_button_color(); - glsafe(::glColor4fv(render_color.data())); - glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); @@ -191,17 +182,46 @@ void GLGizmoPainterBase::render_cursor_circle() const // ensure that the circle is renderered inside the frustrum glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); // ensure that the overlay fits the frustrum near z plane - double gui_scale = camera.get_gui_scale(); + const double gui_scale = camera.get_gui_scale(); glsafe(::glScaled(gui_scale, gui_scale, 1.0)); glsafe(::glPushAttrib(GL_ENABLE_BIT)); glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - ::glBegin(GL_LINE_LOOP); - for (double angle=0; angle<2*M_PI; angle+=M_PI/20.) - ::glVertex2f(GLfloat(center.x()+m_cursor_radius*cos(angle)), GLfloat(center.y()+m_cursor_radius*sin(angle))); - glsafe(::glEnd()); + if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - m_cursor_radius) > EPSILON) { + m_old_center = center; + m_old_cursor_radius = m_cursor_radius; + m_circle.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineLoop; + static const unsigned int StepsCount = 32; + static const float StepSize = 2.0f * float(PI) / float(StepsCount); + entity.positions.reserve(StepsCount); + entity.normals.reserve(StepsCount); + entity.indices.reserve(StepsCount); + for (unsigned int i = 0; i < StepsCount; ++i) { + const float angle = float(i * StepSize); + entity.positions.emplace_back(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i); + } + + init_data.entities.emplace_back(entity); + m_circle.init_from(init_data); + } + + // BBS + ColorRGBA render_color = this->get_cursor_hover_color(); + if (m_button_down == Button::Left) + render_color = this->get_cursor_sphere_left_button_color(); + else if (m_button_down == Button::Right) + render_color = this->get_cursor_sphere_right_button_color(); + + m_circle.set_color(-1, render_color); + m_circle.render(); glsafe(::glPopAttrib()); glsafe(::glPopMatrix()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index de92a426c6..d953c5653c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -225,7 +225,7 @@ public: // from usual on_render method allows to render them before transparent // objects, so they can be seen inside them. The usual on_render is called // after all volumes (including transparent ones) are rendered. - virtual void render_painter_gizmo() const = 0; + virtual void render_painter_gizmo() = 0; virtual const float get_cursor_radius_min() const { return CursorRadiusMin; } virtual const float get_cursor_radius_max() const { return CursorRadiusMax; } @@ -238,8 +238,8 @@ public: protected: virtual void render_triangles(const Selection& selection) const; - void render_cursor() const; - void render_cursor_circle() const; + void render_cursor(); + void render_cursor_circle(); void render_cursor_sphere(const Transform3d& trafo) const; // BBS void render_cursor_height_range(const Transform3d& trafo) const; @@ -300,6 +300,9 @@ protected: bool m_paint_on_overhangs_only = false; float m_highlight_by_angle_threshold_deg = 0.f; + GLModel m_circle; + Vec2d m_old_center{ Vec2d::Zero() }; + float m_old_cursor_radius{ 0.0f }; static constexpr float SmartFillAngleMin = 0.0f; static constexpr float SmartFillAngleMax = 90.f; static constexpr float SmartFillAngleStep = 1.f; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 4a142ba926..534070f644 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -17,10 +17,9 @@ namespace GUI { const float GLGizmoRotate::Offset = 5.0f; -const unsigned int GLGizmoRotate::CircleResolution = 64; const unsigned int GLGizmoRotate::AngleResolution = 64; const unsigned int GLGizmoRotate::ScaleStepsCount = 72; -const float GLGizmoRotate::ScaleStepRad = 2.0f * (float)PI / GLGizmoRotate::ScaleStepsCount; +const float GLGizmoRotate::ScaleStepRad = 2.0f * float(PI) / GLGizmoRotate::ScaleStepsCount; const unsigned int GLGizmoRotate::ScaleLongEvery = 2; const float GLGizmoRotate::ScaleLongTooth = 0.1f; // in percent of radius const unsigned int GLGizmoRotate::SnapRegionsCount = 8; @@ -30,15 +29,7 @@ const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis) : GLGizmoBase(parent, "", -1) , m_axis(axis) - , m_angle(0.0) - , m_center(0.0, 0.0, 0.0) - , m_radius(0.0f) - , m_snap_coarse_in_radius(0.0f) - , m_snap_coarse_out_radius(0.0f) - , m_snap_fine_in_radius(0.0f) - , m_snap_fine_out_radius(0.0f) -{ -} +{} GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) : GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id) @@ -56,7 +47,7 @@ GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) void GLGizmoRotate::set_angle(double angle) { - if (std::abs(angle - 2.0 * (double)PI) < EPSILON) + if (std::abs(angle - 2.0 * double(PI)) < EPSILON) angle = 0.0; m_angle = angle; @@ -71,7 +62,7 @@ std::string GLGizmoRotate::get_tooltip() const case Y: { axis = "Y"; break; } case Z: { axis = "Z"; break; } } - return (m_hover_id == 0 || m_grabbers[0].dragging) ? axis + ": " + format((float)Geometry::rad2deg(m_angle), 2) : ""; + return (m_hover_id == 0 || m_grabbers.front().dragging) ? axis + ": " + format(float(Geometry::rad2deg(m_angle)), 2) : ""; } bool GLGizmoRotate::on_init() @@ -94,34 +85,31 @@ void GLGizmoRotate::on_start_dragging() void GLGizmoRotate::on_update(const UpdateData& data) { - Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection())); + const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection())); - Vec2d orig_dir = Vec2d::UnitX(); - Vec2d new_dir = mouse_pos.normalized(); + const Vec2d orig_dir = Vec2d::UnitX(); + const Vec2d new_dir = mouse_pos.normalized(); double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0)); if (cross2(orig_dir, new_dir) < 0.0) theta = 2.0 * (double)PI - theta; - double len = mouse_pos.norm(); + const double len = mouse_pos.norm(); // snap to coarse snap region - if ((m_snap_coarse_in_radius <= len) && (len <= m_snap_coarse_out_radius)) - { - double step = 2.0 * (double)PI / (double)SnapRegionsCount; - theta = step * (double)std::round(theta / step); + if (m_snap_coarse_in_radius <= len && len <= m_snap_coarse_out_radius) { + const double step = 2.0 * double(PI) / double(SnapRegionsCount); + theta = step * std::round(theta / step); } - else - { + else { // snap to fine snap region (scale) - if ((m_snap_fine_in_radius <= len) && (len <= m_snap_fine_out_radius)) - { - double step = 2.0 * (double)PI / (double)ScaleStepsCount; - theta = step * (double)std::round(theta / step); + if (m_snap_fine_in_radius <= len && len <= m_snap_fine_out_radius) { + const double step = 2.0 * double(PI) / double(ScaleStepsCount); + theta = step * std::round(theta / step); } } - if (theta == 2.0 * (double)PI) + if (theta == 2.0 * double(PI)) theta = 0.0; m_angle = theta; @@ -129,13 +117,13 @@ void GLGizmoRotate::on_update(const UpdateData& data) void GLGizmoRotate::on_render() { - if (!m_grabbers[0].enabled) + if (!m_grabbers.front().enabled) return; const Selection& selection = m_parent.get_selection(); const BoundingBoxf3& box = selection.get_bounding_box(); - if (m_hover_id != 0 && !m_grabbers[0].dragging) { + if (m_hover_id != 0 && !m_grabbers.front().dragging) { m_center = m_custom_center == Vec3d::Zero() ? box.center() : m_custom_center; m_radius = Offset + box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; @@ -144,27 +132,42 @@ void GLGizmoRotate::on_render() m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth); } + const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); + m_grabbers.front().center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); + m_grabbers.front().angles.z() = m_angle; + m_grabbers.front().color = AXES_COLOR[m_axis]; + m_grabbers.front().hover_color = AXES_HOVER_COLOR[m_axis]; + glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); transform_to_local(selection); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data())); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); - render_circle(); + const float radius = Offset + m_parent.get_selection().get_bounding_box().radius(); + const bool radius_changed = std::abs(m_old_radius - radius) > EPSILON; + m_old_radius = radius; - if (m_hover_id != -1) { - render_scale(); - render_snap_radii(); - render_reference_radius(); + ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color); + render_circle(color, radius_changed); + if (m_hover_id != -1) { + const bool hover_radius_changed = std::abs(m_old_hover_radius - radius) > EPSILON; + m_old_hover_radius = radius; + + render_scale(color, hover_radius_changed); + render_snap_radii(color, hover_radius_changed); + render_reference_radius(color, hover_radius_changed); + render_angle_arc(m_highlight_color, hover_radius_changed); + } + + render_grabber_connection(color, radius_changed); + shader->stop_using(); } - glsafe(::glColor4fv(m_highlight_color.data())); - - if (m_hover_id != -1) - render_angle(); - render_grabber(box); render_grabber_extension(box, false); @@ -220,138 +223,223 @@ void GLGizmoRotate3D::load_rotoptimize_state() } } -void GLGizmoRotate::render_circle() const +void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) { - ::glBegin(GL_LINE_LOOP); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) - { - float angle = (float)i * ScaleStepRad; - float x = ::cos(angle) * m_radius; - float y = ::sin(angle) * m_radius; - float z = 0.0f; - ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); + if (!m_circle.is_initialized() || radius_changed) { + m_circle.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineLoop; + entity.positions.reserve(ScaleStepsCount); + entity.normals.reserve(ScaleStepsCount); + entity.indices.reserve(ScaleStepsCount); + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + entity.positions.emplace_back(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i); + } + + init_data.entities.emplace_back(entity); + m_circle.init_from(init_data); } - glsafe(::glEnd()); + + m_circle.set_color(-1, color); + m_circle.render(); } -void GLGizmoRotate::render_scale() const +void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) { - float out_radius_long = m_snap_fine_out_radius; - float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth); + const float out_radius_long = m_snap_fine_out_radius; + const float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth); - ::glBegin(GL_LINES); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) - { - float angle = (float)i * ScaleStepRad; - float cosa = ::cos(angle); - float sina = ::sin(angle); - 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); - } - glsafe(::glEnd()); + if (!m_scale.is_initialized() || radius_changed) { + m_scale.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2 * ScaleStepsCount); + entity.normals.reserve(2 * ScaleStepsCount); + entity.indices.reserve(2 * ScaleStepsCount); + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * m_radius; + const float in_y = sina * m_radius; + const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; + const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; + + entity.positions.emplace_back(in_x, in_y, 0.0f); + entity.positions.emplace_back(out_x, out_y, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i * 2 + 0); + entity.indices.emplace_back(i * 2 + 1); + } + + init_data.entities.emplace_back(entity); + m_scale.init_from(init_data); } -void GLGizmoRotate::render_snap_radii() const -{ - float step = 2.0f * (float)PI / (float)SnapRegionsCount; - - float in_radius = m_radius / 3.0f; - float out_radius = 2.0f * in_radius; - - ::glBegin(GL_LINES); - for (unsigned int i = 0; i < SnapRegionsCount; ++i) - { - float angle = (float)i * step; - float cosa = ::cos(angle); - float sina = ::sin(angle); - 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); - } - glsafe(::glEnd()); + m_scale.set_color(-1, color); + m_scale.render(); } -void GLGizmoRotate::render_reference_radius() const +void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_changed) { - ::glBegin(GL_LINES); - ::glVertex3f(0.0f, 0.0f, 0.0f); - ::glVertex3f((GLfloat)(m_radius * (1.0f + GrabberOffset)), 0.0f, 0.0f); - glsafe(::glEnd()); + const float step = 2.0f * float(PI) / float(SnapRegionsCount); + const float in_radius = m_radius / 3.0f; + const float out_radius = 2.0f * in_radius; + + if (!m_snap_radii.is_initialized() || radius_changed) { + m_snap_radii.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2 * ScaleStepsCount); + entity.normals.reserve(2 * ScaleStepsCount); + entity.indices.reserve(2 * ScaleStepsCount); + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * step); + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * in_radius; + const float in_y = sina * in_radius; + const float out_x = cosa * out_radius; + const float out_y = sina * out_radius; + + entity.positions.emplace_back(in_x, in_y, 0.0f); + entity.positions.emplace_back(out_x, out_y, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i * 2 + 0); + entity.indices.emplace_back(i * 2 + 1); + } + + init_data.entities.emplace_back(entity); + m_snap_radii.init_from(init_data); + } + + m_snap_radii.set_color(-1, color); + m_snap_radii.render(); } -void GLGizmoRotate::render_angle() const +void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_changed) { - float step_angle = (float)m_angle / AngleResolution; - float ex_radius = m_radius * (1.0f + GrabberOffset); + if (!m_reference_radius.is_initialized() || radius_changed) { + m_reference_radius.reset(); - ::glBegin(GL_LINE_STRIP); - for (unsigned int i = 0; i <= AngleResolution; ++i) - { - float angle = (float)i * step_angle; - float x = ::cos(angle) * ex_radius; - float y = ::sin(angle) * ex_radius; - float z = 0.0f; - ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(0.0f, 0.0f, 0.0f); + entity.positions.emplace_back(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f); + entity.normals.reserve(2); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_reference_radius.init_from(init_data); } - glsafe(::glEnd()); + + m_reference_radius.set_color(-1, color); + m_reference_radius.render(); +} + +void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed) +{ + const float step_angle = float(m_angle) / float(AngleResolution); + const float ex_radius = m_radius * (1.0f + GrabberOffset); + + if (!m_angle_arc.is_initialized() || radius_changed) { + m_angle_arc.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineStrip; + entity.positions.reserve(1 + AngleResolution); + entity.normals.reserve(1 + AngleResolution); + entity.indices.reserve(1 + AngleResolution); + for (unsigned int i = 0; i <= AngleResolution; ++i) { + const float angle = float(i) * step_angle; + entity.positions.emplace_back(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i); + } + + init_data.entities.emplace_back(entity); + m_angle_arc.init_from(init_data); + } + + m_angle_arc.set_color(-1, color); + m_angle_arc.render(); +} + +void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radius_changed) +{ + if (!m_grabber_connection.model.is_initialized() || radius_changed || !m_grabber_connection.old_center.isApprox(m_grabbers.front().center)) { + m_grabber_connection.model.reset(); + m_grabber_connection.old_center = m_grabbers.front().center; + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(0.0f, 0.0f, 0.0f); + entity.positions.emplace_back(m_grabbers.front().center.cast()); + entity.normals.reserve(2); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_grabber_connection.model.init_from(init_data); + } + + m_grabber_connection.model.set_color(-1, color); + m_grabber_connection.model.render(); } void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const { - double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); - m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); - m_grabbers[0].angles(2) = m_angle; - m_grabbers[0].color = AXES_COLOR[m_axis]; - m_grabbers[0].hover_color = AXES_HOVER_COLOR[m_axis]; - - glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data())); - - ::glBegin(GL_LINES); - ::glVertex3f(0.0f, 0.0f, 0.0f); - ::glVertex3dv(m_grabbers[0].center.data()); - glsafe(::glEnd()); - - m_grabbers[0].color = m_highlight_color; + m_grabbers.front().color = m_highlight_color; render_grabbers(box); } -void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) const +void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) { double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; //float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); //double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); - ColorRGBA color = m_grabbers[0].color; - if (!picking && m_hover_id != -1) { - color = m_grabbers[0].hover_color; - //color[0] = 1.0f - color[0]; - //color[1] = 1.0f - color[1]; - //color[2] = 1.0f - color[2]; - } + ColorRGBA color = m_grabbers.front().color; + if (!picking && m_hover_id != -1) + color = m_grabbers.front().hover_color; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; - const_cast(&m_cone)->set_color(-1, color); + m_cone.set_color(-1, color); if (!picking) { shader->start_using(); shader->set_uniform("emission_factor", 0.1f); } + const Vec3d& center = m_grabbers.front().center; + glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z())); + glsafe(::glTranslated(center.x(), center.y(), center.z())); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); @@ -359,7 +447,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick m_cone.render(); glsafe(::glPopMatrix()); glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z())); + glsafe(::glTranslated(center.x(), center.y(), center.z())); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); @@ -376,7 +464,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const glsafe(::glTranslated(m_center(0), m_center(1), m_center(2))); if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { - Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); + const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); glsafe(::glMultMatrixd(orient_matrix.data())); } @@ -405,7 +493,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const { - double half_pi = 0.5 * (double)PI; + double half_pi = 0.5 * double(PI); Transform3d m = Transform3d::Identity(); @@ -486,13 +574,13 @@ bool GLGizmoRotate3D::on_is_activable() const void GLGizmoRotate3D::on_start_dragging() { - if ((0 <= m_hover_id) && (m_hover_id < 3)) + if (0 <= m_hover_id && m_hover_id < 3) m_gizmos[m_hover_id].start_dragging(); } void GLGizmoRotate3D::on_stop_dragging() { - if ((0 <= m_hover_id) && (m_hover_id < 3)) + if (0 <= m_hover_id && m_hover_id < 3) m_gizmos[m_hover_id].stop_dragging(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 0f426f26f4..bc546a8956 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -13,7 +13,6 @@ namespace GUI { class GLGizmoRotate : public GLGizmoBase { static const float Offset; - static const unsigned int CircleResolution; static const unsigned int AngleResolution; static const unsigned int ScaleStepsCount; static const float ScaleStepRad; @@ -32,18 +31,29 @@ public: private: Axis m_axis; - double m_angle; - - mutable Vec3d m_custom_center{Vec3d::Zero()}; - mutable Vec3d m_center; - mutable float m_radius; - - mutable float m_snap_coarse_in_radius; - mutable float m_snap_coarse_out_radius; - mutable float m_snap_fine_in_radius; - mutable float m_snap_fine_out_radius; + double m_angle{ 0.0 }; + Vec3d m_custom_center{Vec3d::Zero()}; + Vec3d m_center{ Vec3d::Zero() }; + float m_radius{ 0.0f }; + float m_snap_coarse_in_radius{ 0.0f }; + float m_snap_coarse_out_radius{ 0.0f }; + float m_snap_fine_in_radius{ 0.0f }; + float m_snap_fine_out_radius{ 0.0f }; GLModel m_cone; + GLModel m_circle; + GLModel m_scale; + GLModel m_snap_radii; + GLModel m_reference_radius; + GLModel m_angle_arc; + struct GrabberConnection + { + GLModel model; + Vec3d old_center{ Vec3d::Zero() }; + }; + GrabberConnection m_grabber_connection; + float m_old_radius{ 0.0f }; + float m_old_hover_radius{ 0.0f }; public: GLGizmoRotate(GLCanvas3D& parent, Axis axis); @@ -66,13 +76,14 @@ protected: void on_render_for_picking() override; private: - void render_circle() const; - void render_scale() const; - void render_snap_radii() const; - void render_reference_radius() const; - void render_angle() const; + void render_circle(const ColorRGBA& color, bool radius_changed); + void render_scale(const ColorRGBA& color, bool radius_changed); + void render_snap_radii(const ColorRGBA& color, bool radius_changed); + void render_reference_radius(const ColorRGBA& color, bool radius_changed); + void render_angle_arc(const ColorRGBA& color, bool radius_changed); + void render_grabber_connection(const ColorRGBA& color, bool radius_changed); void render_grabber(const BoundingBoxf3& box) const; - void render_grabber_extension(const BoundingBoxf3& box, bool picking) const; + void render_grabber_extension(const BoundingBoxf3& box, bool picking); void transform_to_local(const Selection& selection) const; // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate @@ -96,8 +107,7 @@ public: Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } - std::string get_tooltip() const override - { + std::string get_tooltip() const override { std::string tooltip = m_gizmos[X].get_tooltip(); if (tooltip.empty()) tooltip = m_gizmos[Y].get_tooltip(); @@ -116,38 +126,32 @@ public: protected: bool on_init() override; std::string on_get_name() const override; - void on_set_state() override - { + void on_set_state() override { for (GLGizmoRotate& g : m_gizmos) g.set_state(m_state); } - void on_set_hover_id() override - { + void on_set_hover_id() override { for (int i = 0; i < 3; ++i) m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); } - void on_enable_grabber(unsigned int id) override - { + void on_enable_grabber(unsigned int id) override { if (id < 3) m_gizmos[id].enable_grabber(0); } - void on_disable_grabber(unsigned int id) override - { + void on_disable_grabber(unsigned int id) override { if (id < 3) m_gizmos[id].disable_grabber(0); } bool on_is_activable() const override; void on_start_dragging() override; void on_stop_dragging() override; - void on_update(const UpdateData& data) override - { + void on_update(const UpdateData& data) override { for (GLGizmoRotate& g : m_gizmos) { g.update(data); } } void on_render() override; - void on_render_for_picking() override - { + void on_render_for_picking() override { for (GLGizmoRotate& g : m_gizmos) { g.render_for_picking(); } @@ -157,10 +161,11 @@ protected: private: - class RotoptimzeWindow { + class RotoptimzeWindow + { ImGuiWrapper *m_imgui = nullptr; - public: + public: struct State { float accuracy = 1.f; int method_id = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 0f98c5dd35..c89af3f0ee 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -24,12 +24,16 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan //BBS: GUI refactor: add obj manipulation GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) : GLGizmoBase(parent, icon_filename, sprite_id) - , m_scale(Vec3d::Ones()) - , m_offset(Vec3d::Zero()) - , m_snap_step(0.05) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) { + m_grabber_connections[0].grabber_indices = { 0, 1 }; + m_grabber_connections[1].grabber_indices = { 2, 3 }; + m_grabber_connections[2].grabber_indices = { 4, 5 }; + m_grabber_connections[3].grabber_indices = { 6, 7 }; + m_grabber_connections[4].grabber_indices = { 7, 8 }; + m_grabber_connections[5].grabber_indices = { 8, 9 }; + m_grabber_connections[6].grabber_indices = { 9, 6 }; } std::string GLGizmoScale3D::get_tooltip() const @@ -46,17 +50,17 @@ std::string GLGizmoScale3D::get_tooltip() const scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast(); if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging) - return "X: " + format(scale(0), 4) + "%"; + return "X: " + format(scale.x(), 4) + "%"; else if (m_hover_id == 2 || m_hover_id == 3 || m_grabbers[2].dragging || m_grabbers[3].dragging) - return "Y: " + format(scale(1), 4) + "%"; + return "Y: " + format(scale.y(), 4) + "%"; else if (m_hover_id == 4 || m_hover_id == 5 || m_grabbers[4].dragging || m_grabbers[5].dragging) - return "Z: " + format(scale(2), 4) + "%"; + return "Z: " + format(scale.z(), 4) + "%"; else if (m_hover_id == 6 || m_hover_id == 7 || m_hover_id == 8 || m_hover_id == 9 || m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging) { - std::string tooltip = "X: " + format(scale(0), 2) + "%\n"; - tooltip += "Y: " + format(scale(1), 2) + "%\n"; - tooltip += "Z: " + format(scale(2), 2) + "%"; + std::string tooltip = "X: " + format(scale.x(), 2) + "%\n"; + tooltip += "Y: " + format(scale.y(), 2) + "%\n"; + tooltip += "Z: " + format(scale.z(), 2) + "%"; return tooltip; } else @@ -71,8 +75,7 @@ void GLGizmoScale3D::enable_ununiversal_scale(bool enable) bool GLGizmoScale3D::on_init() { - for (int i = 0; i < 10; ++i) - { + for (int i = 0; i < 10; ++i) { m_grabbers.push_back(Grabber()); } @@ -106,8 +109,7 @@ bool GLGizmoScale3D::on_is_activable() const void GLGizmoScale3D::on_start_dragging() { - if (m_hover_id != -1) - { + if (m_hover_id != -1) { m_starting.drag_position = m_grabbers[m_hover_id].center; m_starting.plane_center = m_grabbers[4].center; m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center; @@ -115,22 +117,22 @@ void GLGizmoScale3D::on_start_dragging() m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box(); const Vec3d& center = m_starting.box.center(); - m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max(0), center(1), center(2)); - m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min(0), center(1), center(2)); - m_starting.pivots[2] = m_transform * Vec3d(center(0), m_starting.box.max(1), center(2)); - m_starting.pivots[3] = m_transform * Vec3d(center(0), m_starting.box.min(1), center(2)); - m_starting.pivots[4] = m_transform * Vec3d(center(0), center(1), m_starting.box.max(2)); - m_starting.pivots[5] = m_transform * Vec3d(center(0), center(1), m_starting.box.min(2)); + m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); + m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z()); + m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z()); + m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z()); + m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z()); + m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z()); } } void GLGizmoScale3D::on_update(const UpdateData& data) { - if ((m_hover_id == 0) || (m_hover_id == 1)) + if (m_hover_id == 0 || m_hover_id == 1) do_scale_along_axis(X, data); - else if ((m_hover_id == 2) || (m_hover_id == 3)) + else if (m_hover_id == 2 || m_hover_id == 3) do_scale_along_axis(Y, data); - else if ((m_hover_id == 4) || (m_hover_id == 5)) + else if (m_hover_id == 4 || m_hover_id == 5) do_scale_along_axis(Z, data); else if (m_hover_id >= 6) do_scale_uniform(data); @@ -190,24 +192,24 @@ void GLGizmoScale3D::on_render() bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); // x axis - m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), m_box.min(2)); - m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), m_box.min(2)); + m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z()); + m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z()); // y axis - m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), m_box.min(2)); - m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), m_box.min(2)); + m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z()); // z axis do not show 4 - m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)); + m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z()); m_grabbers[4].enabled = false; - m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)); + m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z()); // uniform - m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), m_box.min(2)); - m_grabbers[7].center = m_transform * Vec3d(m_box.max(0), m_box.min(1), m_box.min(2)); - m_grabbers[8].center = m_transform * Vec3d(m_box.max(0), m_box.max(1), m_box.min(2)); - m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), m_box.min(2)); + m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z()); + m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z()); for (int i = 0; i < 6; ++i) { m_grabbers[i].color = AXES_COLOR[i/2]; @@ -228,26 +230,23 @@ void GLGizmoScale3D::on_render() const BoundingBoxf3& selection_box = selection.get_bounding_box(); - float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0); + float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); - //draw connections - - // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) - //if (single_instance || single_volume) { - - if (m_grabbers[4].enabled && m_grabbers[5].enabled) { - glsafe(::glColor4fv(m_grabbers[4].color.data())); - render_grabbers_connection(4, 5); + //draw connections + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) + //if (single_instance || single_volume) { + if (m_grabbers[4].enabled && m_grabbers[5].enabled) + render_grabbers_connection(4, 5, m_grabbers[4].color); + render_grabbers_connection(6, 7, m_grabbers[2].color); + render_grabbers_connection(7, 8, m_grabbers[2].color); + render_grabbers_connection(8, 9, m_grabbers[0].color); + render_grabbers_connection(9, 6, m_grabbers[0].color); + shader->stop_using(); } - glsafe(::glColor4fv(m_grabbers[2].color.data())); - render_grabbers_connection(6, 7); - render_grabbers_connection(8, 9); - - glsafe(::glColor4fv(m_grabbers[0].color.data())); - render_grabbers_connection(7, 8); - render_grabbers_connection(9, 6); - // draw grabbers render_grabbers(grabber_mean_size); } @@ -258,19 +257,52 @@ void GLGizmoScale3D::on_render_for_picking() render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); } -void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const +void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color) { - unsigned int grabbers_count = (unsigned int)m_grabbers.size(); - if ((id_1 < grabbers_count) && (id_2 < grabbers_count)) - { - glLineStipple(1, 0x0FFF); - glEnable(GL_LINE_STIPPLE); - ::glBegin(GL_LINES); - ::glVertex3dv(m_grabbers[id_1].center.data()); - ::glVertex3dv(m_grabbers[id_2].center.data()); - glsafe(::glEnd()); - glDisable(GL_LINE_STIPPLE); + auto grabber_connection = [this](unsigned int id_1, unsigned int id_2) { + for (int i = 0; i < int(m_grabber_connections.size()); ++i) { + if (m_grabber_connections[i].grabber_indices.first == id_1 && m_grabber_connections[i].grabber_indices.second == id_2) + return i; + } + return -1; + }; + + int id = grabber_connection(id_1, id_2); + if (id == -1) + return; + + if (!m_grabber_connections[id].model.is_initialized() || + !m_grabber_connections[id].old_v1.isApprox(m_grabbers[id_1].center) || + !m_grabber_connections[id].old_v2.isApprox(m_grabbers[id_2].center)) { + m_grabber_connections[id].old_v1 = m_grabbers[id_1].center; + m_grabber_connections[id].old_v2 = m_grabbers[id_2].center; + m_grabber_connections[id].model.reset(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(m_grabbers[id_1].center.cast()); + entity.positions.emplace_back(m_grabbers[id_2].center.cast()); + + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_grabber_connections[id].model.init_from(init_data); } + + m_grabber_connections[id].model.set_color(-1, color); + glLineStipple(1, 0x0FFF); + glEnable(GL_LINE_STIPPLE); + m_grabber_connections[id].model.render(); + glDisable(GL_LINE_STIPPLE); } //BBS: add input window for move @@ -283,11 +315,9 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) { double ratio = calc_ratio(data); - if (ratio > 0.0) - { + if (ratio > 0.0) { m_scale(axis) = m_starting.scale(axis) * ratio; - if (m_starting.ctrl_down) - { + if (m_starting.ctrl_down) { double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis); if (m_hover_id == 2 * axis) local_offset *= -1.0; @@ -311,8 +341,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) void GLGizmoScale3D::do_scale_uniform(const UpdateData& data) { double ratio = calc_ratio(data); - if (ratio > 0.0) - { + if (ratio > 0.0) { m_scale = m_starting.scale * ratio; m_offset = Vec3d::Zero(); } @@ -322,11 +351,11 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const { double ratio = 0.0; - Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.pivots[m_hover_id] : m_starting.plane_center; + Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.plane_center; + Vec3d starting_vec = m_starting.drag_position - pivot; double len_starting_vec = starting_vec.norm(); - if (len_starting_vec != 0.0) - { + if (len_starting_vec != 0.0) { Vec3d mouse_dir = data.mouse_ray.unit_vector(); Vec3d plane_normal = m_starting.plane_nromal; if (m_hover_id == 5) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 839c7f6823..b87625a7c1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -32,10 +32,19 @@ class GLGizmoScale3D : public GLGizmoBase mutable Transform3d m_transform; // Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes) mutable Transform3d m_offsets_transform; - Vec3d m_scale; - Vec3d m_offset; - double m_snap_step; + Vec3d m_scale{ Vec3d::Ones() }; + Vec3d m_offset{ Vec3d::Zero() }; + double m_snap_step{ 0.05 }; StartingData m_starting; + + struct GrabberConnection + { + GLModel model; + std::pair grabber_indices; + Vec3d old_v1{ Vec3d::Zero() }; + Vec3d old_v2{ Vec3d::Zero() }; + }; + std::array m_grabber_connections; //BBS: add size adjust related GizmoObjectManipulation* m_object_manipulation; @@ -68,7 +77,7 @@ protected: virtual void on_render_input_window(float x, float y, float bottom_limit); private: - void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const; + void render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color); void do_scale_along_axis(Axis axis, const UpdateData& data); void do_scale_uniform(const UpdateData& data); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 9de9d2c903..04e32898d6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -62,7 +62,7 @@ std::string GLGizmoSeam::on_get_name() const -void GLGizmoSeam::render_painter_gizmo() const +void GLGizmoSeam::render_painter_gizmo() { const Selection& selection = m_parent.get_selection(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp index 94cefa7f07..abfd4c28aa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp @@ -10,7 +10,7 @@ class GLGizmoSeam : public GLGizmoPainterBase public: GLGizmoSeam(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - void render_painter_gizmo() const override; + void render_painter_gizmo() override; //BBS bool on_key_down_select_tool_type(int keyCode); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 87c9a00c9e..8f13dc8143 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -692,7 +692,7 @@ void GLGizmosManager::render_current_gizmo() const m_gizmos[m_current]->render(); } -void GLGizmosManager::render_painter_gizmo() const +void GLGizmosManager::render_painter_gizmo() { // This function shall only be called when current gizmo is // derived from GLGizmoPainterBase. diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index fefb85b6b9..6237d4e193 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -31,16 +31,24 @@ class CommonGizmosDataPool; class GizmoObjectManipulation; class Rect { - float m_left; - float m_top; - float m_right; - float m_bottom; + float m_left{ 0.0f }; + float m_top{ 0.0f }; + float m_right{ 0.0f }; + float m_bottom{ 0.0f }; public: - Rect() : m_left(0.0f) , m_top(0.0f) , m_right(0.0f) , m_bottom(0.0f) {} - + Rect() = default; Rect(float left, float top, float right, float bottom) : m_left(left) , m_top(top) , m_right(right) , m_bottom(bottom) {} + bool operator == (const Rect& other) { + if (std::abs(m_left - other.m_left) > EPSILON) return false; + if (std::abs(m_top - other.m_top) > EPSILON) return false; + if (std::abs(m_right - other.m_right) > EPSILON) return false; + if (std::abs(m_bottom - other.m_bottom) > EPSILON) return false; + return true; + } + bool operator != (const Rect& other) { return !operator==(other); } + float get_left() const { return m_left; } void set_left(float left) { m_left = left; } @@ -287,7 +295,7 @@ public: void on_change_color_mode(bool is_dark); void render_current_gizmo() const; void render_current_gizmo_for_picking_pass() const; - void render_painter_gizmo() const; + void render_painter_gizmo(); void render_painter_assemble_view() const; void render_overlay();