enricoturri1966 2023-10-21 12:06:59 +08:00 committed by Noisyfox
parent f6a3421e2a
commit 7e04448b7a
23 changed files with 742 additions and 449 deletions

View file

@ -326,40 +326,36 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>&
Vec3d angles1 = Vec3d::Zero(); Vec3d angles1 = Vec3d::Zero();
Vec3d angles2 = Vec3d::Zero(); Vec3d angles2 = Vec3d::Zero();
// BBS: rotation_matrix(2, 0) may be slighterly larger than 1 due to numerical accuracy // 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) if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1) {
{ angles1.z() = 0.0;
angles1(2) = 0.0; if (rotation_matrix(2, 0) < 0.0) { // == -1.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));
angles1(1) = 0.5 * (double)PI;
angles1(0) = angles1(2) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2));
} }
else // == 1.0 else { // == 1.0
{ angles1.y() = - 0.5 * double(PI);
angles1(1) = - 0.5 * (double)PI; angles1.x() = - angles1.y() + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2));
angles1(0) = - angles1(2) + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2));
} }
angles2 = angles1; angles2 = angles1;
} }
else else {
{ angles1.y() = -::asin(rotation_matrix(2, 0));
angles1(1) = -::asin(rotation_matrix(2, 0)); const double inv_cos1 = 1.0 / ::cos(angles1.y());
double inv_cos1 = 1.0 / ::cos(angles1(1)); angles1.x() = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1);
angles1(0) = ::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);
angles1(2) = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1);
angles2(1) = (double)PI - angles1(1); angles2.y() = double(PI) - angles1.y();
double inv_cos2 = 1.0 / ::cos(angles2(1)); const double inv_cos2 = 1.0 / ::cos(angles2.y());
angles2(0) = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2); angles2.x() = ::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.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) // 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 // but there are other use-cases were it does not
// We need to improve it // We need to improve it
double min_1 = angles1.cwiseAbs().minCoeff(); const double min_1 = angles1.cwiseAbs().minCoeff();
double min_2 = angles2.cwiseAbs().minCoeff(); const double min_2 = angles2.cwiseAbs().minCoeff();
bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm())); const bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm()));
return use_1 ? angles1 : angles2; return use_1 ? angles1 : angles2;
} }
@ -423,14 +419,6 @@ Transform3d rotation_transform(const Vec3d& rotation)
return transform; 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 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); 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) void Transformation::set_offset(const Vec3d& offset)
{ {
set_offset(X, offset(0)); set_offset(X, offset.x());
set_offset(Y, offset(1)); set_offset(Y, offset.y());
set_offset(Z, offset(2)); set_offset(Z, offset.z());
} }
void Transformation::set_offset(Axis axis, double offset) void Transformation::set_offset(Axis axis, double offset)
{ {
if (m_offset(axis) != offset) if (m_offset(axis) != offset) {
{
m_offset(axis) = offset; m_offset(axis) = offset;
m_dirty = true; m_dirty = true;
} }
@ -472,19 +459,18 @@ void Transformation::set_offset(Axis axis, double offset)
void Transformation::set_rotation(const Vec3d& rotation) void Transformation::set_rotation(const Vec3d& rotation)
{ {
set_rotation(X, rotation(0)); set_rotation(X, rotation.x());
set_rotation(Y, rotation(1)); set_rotation(Y, rotation.y());
set_rotation(Z, rotation(2)); set_rotation(Z, rotation.z());
} }
void Transformation::set_rotation(Axis axis, double rotation) void Transformation::set_rotation(Axis axis, double rotation)
{ {
rotation = angle_to_0_2PI(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; rotation = 0.0;
if (m_rotation(axis) != rotation) if (m_rotation(axis) != rotation) {
{
m_rotation(axis) = rotation; m_rotation(axis) = rotation;
m_dirty = true; m_dirty = true;
} }
@ -492,15 +478,14 @@ void Transformation::set_rotation(Axis axis, double rotation)
void Transformation::set_scaling_factor(const Vec3d& scaling_factor) void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
{ {
set_scaling_factor(X, scaling_factor(0)); set_scaling_factor(X, scaling_factor.x());
set_scaling_factor(Y, scaling_factor(1)); set_scaling_factor(Y, scaling_factor.y());
set_scaling_factor(Z, scaling_factor(2)); set_scaling_factor(Z, scaling_factor.z());
} }
void Transformation::set_scaling_factor(Axis axis, double scaling_factor) 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_scaling_factor(axis) = std::abs(scaling_factor);
m_dirty = true; m_dirty = true;
} }
@ -508,9 +493,9 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
void Transformation::set_mirror(const Vec3d& mirror) void Transformation::set_mirror(const Vec3d& mirror)
{ {
set_mirror(X, mirror(0)); set_mirror(X, mirror.x());
set_mirror(Y, mirror(1)); set_mirror(Y, mirror.y());
set_mirror(Z, mirror(2)); set_mirror(Z, mirror.z());
} }
void Transformation::set_mirror(Axis axis, double mirror) 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) else if (abs_mirror != 1.0)
mirror /= abs_mirror; mirror /= abs_mirror;
if (m_mirror(axis) != mirror) if (m_mirror(axis) != mirror) {
{
m_mirror(axis) = mirror; m_mirror(axis) = mirror;
m_dirty = true; 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 // 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 // in which case we reorient it back to right handed by mirroring the x axis
Vec3d mirror = Vec3d::Ones(); Vec3d mirror = Vec3d::Ones();
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) {
{ mirror.x() = -1.0;
mirror(0) = -1.0;
// remove mirror // remove mirror
m3x3.col(0) *= -1.0; 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 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( m_matrix = Geometry::assemble_transform(
dont_translate ? Vec3d::Zero() : m_offset, dont_translate ? Vec3d::Zero() : m_offset,
dont_rotate ? Vec3d::Zero() : m_rotation, dont_rotate ? Vec3d::Zero() : m_rotation,
@ -609,8 +591,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
// Just set the inverse. // Just set the inverse.
out.set_from_transform(instance_transformation.get_matrix(true).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. // Anisotropic scaling, rotation by multiples of ninety degrees.
Eigen::Matrix3d instance_rotation_trafo = Eigen::Matrix3d instance_rotation_trafo =
(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * (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)); 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_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_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z())));
out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
} }
else else
{ {
@ -663,19 +644,15 @@ Transform3d transform3d_from_string(const std::string& transform_str)
assert(is_decimal_separator_point()); // for atof assert(is_decimal_separator_point()); // for atof
Transform3d transform = Transform3d::Identity(); Transform3d transform = Transform3d::Identity();
if (!transform_str.empty()) if (!transform_str.empty()) {
{
std::vector<std::string> mat_elements_str; std::vector<std::string> mat_elements_str;
boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on); boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on);
unsigned int size = (unsigned int)mat_elements_str.size(); const unsigned int size = (unsigned int)mat_elements_str.size();
if (size == 16) if (size == 16) {
{
unsigned int i = 0; unsigned int i = 0;
for (unsigned int r = 0; r < 4; ++r) for (unsigned int r = 0; r < 4; ++r) {
{ for (unsigned int c = 0; c < 4; ++c) {
for (unsigned int c = 0; c < 4; ++c)
{
transform(r, c) = ::atof(mat_elements_str[i++].c_str()); 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 return
// From the current coordinate system to world. // 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. // 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. // 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) 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)); const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis(); const Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle(); const double angle = angle_axis.angle();
#ifndef NDEBUG #ifndef NDEBUG
if (std::abs(angle) > 1e-8) { if (std::abs(angle) > 1e-8) {
assert(std::abs(axis.x()) < 1e-8); assert(std::abs(axis.x()) < 1e-8);

View file

@ -361,25 +361,23 @@ class Transformation
{ {
struct Flags struct Flags
{ {
bool dont_translate; bool dont_translate{ true };
bool dont_rotate; bool dont_rotate{ true };
bool dont_scale; bool dont_scale{ true };
bool dont_mirror; bool dont_mirror{ true };
Flags();
bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const; 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); void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror);
}; };
Vec3d m_offset; // In unscaled coordinates Vec3d m_offset{ Vec3d::Zero() }; // In unscaled coordinates
Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point Vec3d m_rotation{ Vec3d::Zero() }; // Rotation around the three axes, in radians around mesh center point
Vec3d m_scaling_factor; // Scaling factors along the three axes Vec3d m_scaling_factor{ Vec3d::Ones() }; // Scaling factors along the three axes
Vec3d m_mirror; // Mirroring 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 Flags m_flags;
mutable bool m_dirty; mutable bool m_dirty{ false };
public: public:
Transformation(); 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? // Is the angle close to a multiple of 90 degrees?
inline bool is_rotation_ninety_degrees(double a) 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) if (a > 0.25 * PI)
a = 0.5 * PI - a; a = 0.5 * PI - a;
return a < 0.001; return a < 0.001;

View file

@ -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 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; const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x;
// Baseline bool bar_rect_changed = m_profile.old_bar_rect != bar_rect;
glsafe(::glColor3f(0.0f, 0.0f, 0.0f)); m_profile.old_bar_rect = bar_rect;
::glBegin(GL_LINE_STRIP);
::glVertex2f(x, bar_rect.get_bottom());
::glVertex2f(x, bar_rect.get_top());
glsafe(::glEnd());
// Curve // Baseline
glsafe(::glColor3f(0.0f, 0.0f, 1.0f)); if (!m_profile.baseline.is_initialized() || bar_rect_changed) {
::glBegin(GL_LINE_STRIP); m_profile.old_bar_rect = bar_rect;
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); GLModel::InitializationData init_data;
glsafe(::glEnd()); 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) 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: default:
case GLVolumeCollection::ERenderType::Opaque: case GLVolumeCollection::ERenderType::Opaque:
{ {
const GLGizmosManager& gm = get_gizmos_manager(); GLGizmosManager& gm = get_gizmos_manager();
if (dynamic_cast<GLGizmoPainterBase*>(gm.get_current()) == nullptr) if (dynamic_cast<GLGizmoPainterBase*>(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)) { 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 #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(::glDisable(GL_DEPTH_TEST));
glsafe(::glLineWidth(2.0f)); glsafe(::glLineWidth(2.0f));
::glBegin(GL_LINES);
const Vec3d& target = wxGetApp().plater()->get_camera().get_target(); const Vec3d& target = wxGetApp().plater()->get_camera().get_target();
// draw line for x axis bool target_changed = !m_camera_target.target.isApprox(target);
::glColor3f(1.0f, 0.0f, 0.0f); m_camera_target.target = target;
::glVertex3d(target(0) - half_length, target(1), target(2));
::glVertex3d(target(0) + half_length, target(1), target(2)); for (int i = 0; i < 3; ++i) {
// draw line for y axis if (!m_camera_target.axis[i].is_initialized() || target_changed) {
::glColor3f(0.0f, 1.0f, 0.0f); m_camera_target.axis[i].reset();
::glVertex3d(target(0), target(1) - half_length, target(2));
::glVertex3d(target(0), target(1) + half_length, target(2)); GLModel::InitializationData init_data;
// draw line for z axis GLModel::InitializationData::Entity entity;
::glColor3f(0.0f, 0.0f, 1.0f); entity.type = GLModel::PrimitiveType::Lines;
::glVertex3d(target(0), target(1), target(2) - half_length); entity.positions.reserve(2);
::glVertex3d(target(0), target(1), target(2) + half_length); if (i == X) {
glsafe(::glEnd()); 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 #endif // ENABLE_SHOW_CAMERA_TARGET

View file

@ -257,6 +257,14 @@ class GLCanvas3D
int last_object_id{ -1 }; int last_object_id{ -1 };
float last_z{ 0.0f }; float last_z{ 0.0f };
LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE }; LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE };
struct Profile
{
GLModel baseline;
GLModel profile;
Rect old_bar_rect;
std::vector<double> old_layer_height_profile;
};
Profile m_profile;
LayersEditing() = default; LayersEditing() = default;
~LayersEditing(); ~LayersEditing();
@ -698,6 +706,15 @@ public:
} }
m_gizmo_highlighter; m_gizmo_highlighter;
#if ENABLE_SHOW_CAMERA_TARGET
struct CameraTarget
{
std::array<GLModel, 3> axis;
Vec3d target{ Vec3d::Zero() };
};
CameraTarget m_camera_target;
#endif // ENABLE_SHOW_CAMERA_TARGET
public: public:
explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed); explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed);
~GLCanvas3D(); ~GLCanvas3D();
@ -1139,7 +1156,7 @@ private:
void _render_assemble_control() const; void _render_assemble_control() const;
void _render_assemble_info() const; void _render_assemble_info() const;
#if ENABLE_SHOW_CAMERA_TARGET #if ENABLE_SHOW_CAMERA_TARGET
void _render_camera_target() const; void _render_camera_target();
#endif // ENABLE_SHOW_CAMERA_TARGET #endif // ENABLE_SHOW_CAMERA_TARGET
void _render_sla_slices(); void _render_sla_slices();
void _render_selection_sidebar_hints(); void _render_selection_sidebar_hints();

View file

@ -69,7 +69,7 @@ namespace GUI {
m_state = Off; m_state = Off;
} }
void GLSelectionRectangle::render(const GLCanvas3D& canvas) const void GLSelectionRectangle::render(const GLCanvas3D& canvas)
{ {
if (!is_dragging()) if (!is_dragging())
return; return;
@ -92,11 +92,6 @@ namespace GUI {
float bottom = (float)std::min(start(1), end(1)) * inv_zoom; float bottom = (float)std::min(start(1), end(1)) * inv_zoom;
glsafe(::glLineWidth(1.5f)); 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)); glsafe(::glDisable(GL_DEPTH_TEST));
@ -112,12 +107,46 @@ namespace GUI {
glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE)); glsafe(::glEnable(GL_LINE_STIPPLE));
::glBegin(GL_LINE_LOOP); GLShaderProgram* shader = wxGetApp().get_shader("flat");
::glVertex2f((GLfloat)left, (GLfloat)bottom); if (shader != nullptr) {
::glVertex2f((GLfloat)right, (GLfloat)bottom); shader->start_using();
::glVertex2f((GLfloat)right, (GLfloat)top);
::glVertex2f((GLfloat)left, (GLfloat)top); if (!m_rectangle.is_initialized() || !m_old_start_corner.isApprox(m_start_corner) || !m_old_end_corner.isApprox(m_end_corner)) {
glsafe(::glEnd()); 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()); glsafe(::glPopAttrib());

View file

@ -2,6 +2,7 @@
#define slic3r_GLSelectionRectangle_hpp_ #define slic3r_GLSelectionRectangle_hpp_
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include "GLModel.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -30,7 +31,7 @@ public:
// Disables the rectangle. // Disables the rectangle.
void stop_dragging(); void stop_dragging();
void render(const GLCanvas3D& canvas) const; void render(const GLCanvas3D& canvas);
bool is_dragging() const { return m_state != Off; } bool is_dragging() const { return m_state != Off; }
EState get_state() const { return m_state; } 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)); } float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); }
private: private:
EState m_state = Off; EState m_state{ Off };
Vec2d m_start_corner; Vec2d m_start_corner{ Vec2d::Zero() };
Vec2d m_end_corner; Vec2d m_end_corner{ Vec2d::Zero() };
GLModel m_rectangle;
Vec2d m_old_start_corner{ Vec2d::Zero() };
Vec2d m_old_end_corner{ Vec2d::Zero() };
}; };

View file

@ -33,7 +33,8 @@ std::pair<bool, std::string> GLShadersManager::init()
bool valid = true; 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" }); 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 // 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" }); valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });

View file

@ -105,7 +105,7 @@ bool GLGizmoFdmSupports::on_init()
return true; return true;
} }
void GLGizmoFdmSupports::render_painter_gizmo() const void GLGizmoFdmSupports::render_painter_gizmo()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();

View file

@ -15,7 +15,7 @@ class GLGizmoFdmSupports : public GLGizmoPainterBase
public: public:
GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); 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 //BBS: add edit state
enum EditState { enum EditState {

View file

@ -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(); const Selection& selection = m_parent.get_selection();

View file

@ -67,7 +67,7 @@ public:
GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoMmuSegmentation() override = default; ~GLGizmoMmuSegmentation() override = default;
void render_painter_gizmo() const override; void render_painter_gizmo() override;
void set_painter_gizmo_data(const Selection& selection) override; void set_painter_gizmo_data(const Selection& selection) override;

View file

@ -23,11 +23,6 @@ const double GLGizmoMove3D::Offset = 10.0;
//BBS: GUI refactor: add obj manipulation //BBS: GUI refactor: add obj manipulation
GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id) : 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 //BBS: GUI refactor: add obj manipulation
, m_object_manipulation(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)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
// draw grabbers auto render_grabber_connection = [this, &center](unsigned int id) {
for (unsigned int i = 0; i < 3; ++i) { if (m_grabbers[id].enabled) {
if (m_grabbers[i].enabled) render_grabber_extension((Axis) i, box, false); 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<float>());
entity.positions.emplace_back(m_grabbers[id].center.cast<float>());
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); glLineStipple(1, 0x0FFF);
glEnable(GL_LINE_STIPPLE); glEnable(GL_LINE_STIPPLE);
::glBegin(GL_LINES); m_grabber_connections[id].model.render();
::glVertex3dv(center.data());
// use extension center
::glVertex3dv(m_grabbers[i].center.data());
glsafe(::glEnd());
glDisable(GL_LINE_STIPPLE); 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);
} }
} }

View file

@ -15,15 +15,19 @@ class GLGizmoMove3D : public GLGizmoBase
{ {
static const double Offset; static const double Offset;
Vec3d m_displacement; Vec3d m_displacement{ Vec3d::Zero() };
double m_snap_step{ 1.0 };
double m_snap_step; Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() };
Vec3d m_starting_drag_position; Vec3d m_starting_box_bottom_center{ Vec3d::Zero() };
Vec3d m_starting_box_center;
Vec3d m_starting_box_bottom_center;
GLModel m_vbo_cone; GLModel m_vbo_cone;
struct GrabberConnection
{
GLModel model;
Vec3d old_center{ Vec3d::Zero() };
};
std::array<GrabberConnection, 3> m_grabber_connections;
//BBS: add size adjust related //BBS: add size adjust related
GizmoObjectManipulation* m_object_manipulation; GizmoObjectManipulation* m_object_manipulation;

View file

@ -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. // First check that the mouse pointer is on an object.
const ModelObject* mo = m_c->selection_info()->model_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(); const Camera &camera = wxGetApp().plater()->get_camera();
auto zoom = (float) camera.get_zoom(); const float zoom = float(camera.get_zoom());
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; const float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size(); const Size cnv_size = m_parent.get_canvas_size();
float cnv_half_width = 0.5f * (float) cnv_size.get_width(); const float cnv_half_width = 0.5f * float(cnv_size.get_width());
float cnv_half_height = 0.5f * (float) cnv_size.get_height(); const float cnv_half_height = 0.5f * float(cnv_size.get_height());
if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) if (cnv_half_width == 0.0f || cnv_half_height == 0.0f)
return; return;
Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); const Vec2d mouse_pos(m_parent.get_local_mouse_position().x(), m_parent.get_local_mouse_position().y());
Vec2d center(mouse_pos(0) - cnv_half_width, cnv_half_height - mouse_pos(1)); Vec2d center(mouse_pos.x() - cnv_half_width, cnv_half_height - mouse_pos.y());
center = center * inv_zoom; center = center * inv_zoom;
glsafe(::glLineWidth(1.5f)); 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(::glDisable(GL_DEPTH_TEST));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
@ -191,17 +182,46 @@ void GLGizmoPainterBase::render_cursor_circle() const
// ensure that the circle is renderered inside the frustrum // ensure that the circle is renderered inside the frustrum
glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5)));
// ensure that the overlay fits the frustrum near z plane // 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(::glScaled(gui_scale, gui_scale, 1.0));
glsafe(::glPushAttrib(GL_ENABLE_BIT)); glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE)); glsafe(::glEnable(GL_LINE_STIPPLE));
::glBegin(GL_LINE_LOOP); if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - m_cursor_radius) > EPSILON) {
for (double angle=0; angle<2*M_PI; angle+=M_PI/20.) m_old_center = center;
::glVertex2f(GLfloat(center.x()+m_cursor_radius*cos(angle)), GLfloat(center.y()+m_cursor_radius*sin(angle))); m_old_cursor_radius = m_cursor_radius;
glsafe(::glEnd()); 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(::glPopAttrib());
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());

View file

@ -225,7 +225,7 @@ public:
// from usual on_render method allows to render them before transparent // 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 // objects, so they can be seen inside them. The usual on_render is called
// after all volumes (including transparent ones) are rendered. // 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_min() const { return CursorRadiusMin; }
virtual const float get_cursor_radius_max() const { return CursorRadiusMax; } virtual const float get_cursor_radius_max() const { return CursorRadiusMax; }
@ -238,8 +238,8 @@ public:
protected: protected:
virtual void render_triangles(const Selection& selection) const; virtual void render_triangles(const Selection& selection) const;
void render_cursor() const; void render_cursor();
void render_cursor_circle() const; void render_cursor_circle();
void render_cursor_sphere(const Transform3d& trafo) const; void render_cursor_sphere(const Transform3d& trafo) const;
// BBS // BBS
void render_cursor_height_range(const Transform3d& trafo) const; void render_cursor_height_range(const Transform3d& trafo) const;
@ -300,6 +300,9 @@ protected:
bool m_paint_on_overhangs_only = false; bool m_paint_on_overhangs_only = false;
float m_highlight_by_angle_threshold_deg = 0.f; 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 SmartFillAngleMin = 0.0f;
static constexpr float SmartFillAngleMax = 90.f; static constexpr float SmartFillAngleMax = 90.f;
static constexpr float SmartFillAngleStep = 1.f; static constexpr float SmartFillAngleStep = 1.f;

View file

@ -17,10 +17,9 @@ namespace GUI {
const float GLGizmoRotate::Offset = 5.0f; const float GLGizmoRotate::Offset = 5.0f;
const unsigned int GLGizmoRotate::CircleResolution = 64;
const unsigned int GLGizmoRotate::AngleResolution = 64; const unsigned int GLGizmoRotate::AngleResolution = 64;
const unsigned int GLGizmoRotate::ScaleStepsCount = 72; 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 unsigned int GLGizmoRotate::ScaleLongEvery = 2;
const float GLGizmoRotate::ScaleLongTooth = 0.1f; // in percent of radius const float GLGizmoRotate::ScaleLongTooth = 0.1f; // in percent of radius
const unsigned int GLGizmoRotate::SnapRegionsCount = 8; 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) GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
: GLGizmoBase(parent, "", -1) : GLGizmoBase(parent, "", -1)
, m_axis(axis) , 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) GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
: GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id) : 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) 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; angle = 0.0;
m_angle = angle; m_angle = angle;
@ -71,7 +62,7 @@ std::string GLGizmoRotate::get_tooltip() const
case Y: { axis = "Y"; break; } case Y: { axis = "Y"; break; }
case Z: { axis = "Z"; 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() bool GLGizmoRotate::on_init()
@ -94,34 +85,31 @@ void GLGizmoRotate::on_start_dragging()
void GLGizmoRotate::on_update(const UpdateData& data) 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(); const Vec2d orig_dir = Vec2d::UnitX();
Vec2d new_dir = mouse_pos.normalized(); const Vec2d new_dir = mouse_pos.normalized();
double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0)); double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0));
if (cross2(orig_dir, new_dir) < 0.0) if (cross2(orig_dir, new_dir) < 0.0)
theta = 2.0 * (double)PI - theta; theta = 2.0 * (double)PI - theta;
double len = mouse_pos.norm(); const double len = mouse_pos.norm();
// snap to coarse snap region // snap to coarse snap region
if ((m_snap_coarse_in_radius <= len) && (len <= m_snap_coarse_out_radius)) if (m_snap_coarse_in_radius <= len && len <= m_snap_coarse_out_radius) {
{ const double step = 2.0 * double(PI) / double(SnapRegionsCount);
double step = 2.0 * (double)PI / (double)SnapRegionsCount; theta = step * std::round(theta / step);
theta = step * (double)std::round(theta / step);
} }
else else {
{
// snap to fine snap region (scale) // snap to fine snap region (scale)
if ((m_snap_fine_in_radius <= len) && (len <= m_snap_fine_out_radius)) if (m_snap_fine_in_radius <= len && len <= m_snap_fine_out_radius) {
{ const double step = 2.0 * double(PI) / double(ScaleStepsCount);
double step = 2.0 * (double)PI / (double)ScaleStepsCount; theta = step * std::round(theta / step);
theta = step * (double)std::round(theta / step);
} }
} }
if (theta == 2.0 * (double)PI) if (theta == 2.0 * double(PI))
theta = 0.0; theta = 0.0;
m_angle = theta; m_angle = theta;
@ -129,13 +117,13 @@ void GLGizmoRotate::on_update(const UpdateData& data)
void GLGizmoRotate::on_render() void GLGizmoRotate::on_render()
{ {
if (!m_grabbers[0].enabled) if (!m_grabbers.front().enabled)
return; return;
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const BoundingBoxf3& box = selection.get_bounding_box(); 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_center = m_custom_center == Vec3d::Zero() ? box.center() : m_custom_center;
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f; 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); 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(::glEnable(GL_DEPTH_TEST));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
transform_to_local(selection); transform_to_local(selection);
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); 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) { ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color);
render_scale(); render_circle(color, radius_changed);
render_snap_radii(); if (m_hover_id != -1) {
render_reference_radius(); 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(box);
render_grabber_extension(box, false); 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); if (!m_circle.is_initialized() || radius_changed) {
for (unsigned int i = 0; i < ScaleStepsCount; ++i) m_circle.reset();
{
float angle = (float)i * ScaleStepRad; GLModel::InitializationData init_data;
float x = ::cos(angle) * m_radius; GLModel::InitializationData::Entity entity;
float y = ::sin(angle) * m_radius; entity.type = GLModel::PrimitiveType::LineLoop;
float z = 0.0f; entity.positions.reserve(ScaleStepsCount);
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); 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; const float out_radius_long = m_snap_fine_out_radius;
float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth); const float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth);
::glBegin(GL_LINES); if (!m_scale.is_initialized() || radius_changed) {
for (unsigned int i = 0; i < ScaleStepsCount; ++i) m_scale.reset();
{
float angle = (float)i * ScaleStepRad; GLModel::InitializationData init_data;
float cosa = ::cos(angle); GLModel::InitializationData::Entity entity;
float sina = ::sin(angle); entity.type = GLModel::PrimitiveType::Lines;
float in_x = cosa * m_radius; entity.positions.reserve(2 * ScaleStepsCount);
float in_y = sina * m_radius; entity.normals.reserve(2 * ScaleStepsCount);
float in_z = 0.0f; entity.indices.reserve(2 * ScaleStepsCount);
float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; const float angle = float(i * ScaleStepRad);
float out_z = 0.0f; const float cosa = ::cos(angle);
::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); const float sina = ::sin(angle);
::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); const float in_x = cosa * m_radius;
} const float in_y = sina * m_radius;
glsafe(::glEnd()); 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 m_scale.set_color(-1, color);
{ m_scale.render();
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());
} }
void GLGizmoRotate::render_reference_radius() const void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_changed)
{ {
::glBegin(GL_LINES); const float step = 2.0f * float(PI) / float(SnapRegionsCount);
::glVertex3f(0.0f, 0.0f, 0.0f); const float in_radius = m_radius / 3.0f;
::glVertex3f((GLfloat)(m_radius * (1.0f + GrabberOffset)), 0.0f, 0.0f); const float out_radius = 2.0f * in_radius;
glsafe(::glEnd());
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; if (!m_reference_radius.is_initialized() || radius_changed) {
float ex_radius = m_radius * (1.0f + GrabberOffset); m_reference_radius.reset();
::glBegin(GL_LINE_STRIP); GLModel::InitializationData init_data;
for (unsigned int i = 0; i <= AngleResolution; ++i) GLModel::InitializationData::Entity entity;
{ entity.type = GLModel::PrimitiveType::Lines;
float angle = (float)i * step_angle; entity.positions.reserve(2);
float x = ::cos(angle) * ex_radius; entity.positions.emplace_back(0.0f, 0.0f, 0.0f);
float y = ::sin(angle) * ex_radius; entity.positions.emplace_back(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f);
float z = 0.0f; entity.normals.reserve(2);
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); 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<float>());
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 void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
{ {
double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); m_grabbers.front().color = m_highlight_color;
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;
render_grabbers(box); 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; 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); //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); //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; ColorRGBA color = m_grabbers.front().color;
if (!picking && m_hover_id != -1) { if (!picking && m_hover_id != -1)
color = m_grabbers[0].hover_color; color = m_grabbers.front().hover_color;
//color[0] = 1.0f - color[0];
//color[1] = 1.0f - color[1];
//color[2] = 1.0f - color[2];
}
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr) if (shader == nullptr)
return; return;
const_cast<GLModel*>(&m_cone)->set_color(-1, color); m_cone.set_color(-1, color);
if (!picking) { if (!picking) {
shader->start_using(); shader->start_using();
shader->set_uniform("emission_factor", 0.1f); shader->set_uniform("emission_factor", 0.1f);
} }
const Vec3d& center = m_grabbers.front().center;
glsafe(::glPushMatrix()); 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(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); 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(); m_cone.render();
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
glsafe(::glPushMatrix()); 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(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); 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))); glsafe(::glTranslated(m_center(0), m_center(1), m_center(2)));
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { 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())); 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 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(); Transform3d m = Transform3d::Identity();
@ -486,13 +574,13 @@ bool GLGizmoRotate3D::on_is_activable() const
void GLGizmoRotate3D::on_start_dragging() 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(); m_gizmos[m_hover_id].start_dragging();
} }
void GLGizmoRotate3D::on_stop_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(); m_gizmos[m_hover_id].stop_dragging();
} }

View file

@ -13,7 +13,6 @@ namespace GUI {
class GLGizmoRotate : public GLGizmoBase class GLGizmoRotate : public GLGizmoBase
{ {
static const float Offset; static const float Offset;
static const unsigned int CircleResolution;
static const unsigned int AngleResolution; static const unsigned int AngleResolution;
static const unsigned int ScaleStepsCount; static const unsigned int ScaleStepsCount;
static const float ScaleStepRad; static const float ScaleStepRad;
@ -32,18 +31,29 @@ public:
private: private:
Axis m_axis; Axis m_axis;
double m_angle; double m_angle{ 0.0 };
Vec3d m_custom_center{Vec3d::Zero()};
mutable Vec3d m_custom_center{Vec3d::Zero()}; Vec3d m_center{ Vec3d::Zero() };
mutable Vec3d m_center; float m_radius{ 0.0f };
mutable float m_radius; float m_snap_coarse_in_radius{ 0.0f };
float m_snap_coarse_out_radius{ 0.0f };
mutable float m_snap_coarse_in_radius; float m_snap_fine_in_radius{ 0.0f };
mutable float m_snap_coarse_out_radius; float m_snap_fine_out_radius{ 0.0f };
mutable float m_snap_fine_in_radius;
mutable float m_snap_fine_out_radius;
GLModel m_cone; 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: public:
GLGizmoRotate(GLCanvas3D& parent, Axis axis); GLGizmoRotate(GLCanvas3D& parent, Axis axis);
@ -66,13 +76,14 @@ protected:
void on_render_for_picking() override; void on_render_for_picking() override;
private: private:
void render_circle() const; void render_circle(const ColorRGBA& color, bool radius_changed);
void render_scale() const; void render_scale(const ColorRGBA& color, bool radius_changed);
void render_snap_radii() const; void render_snap_radii(const ColorRGBA& color, bool radius_changed);
void render_reference_radius() const; void render_reference_radius(const ColorRGBA& color, bool radius_changed);
void render_angle() const; 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(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; 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 // 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()); } 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)); } 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(); std::string tooltip = m_gizmos[X].get_tooltip();
if (tooltip.empty()) if (tooltip.empty())
tooltip = m_gizmos[Y].get_tooltip(); tooltip = m_gizmos[Y].get_tooltip();
@ -116,38 +126,32 @@ public:
protected: protected:
bool on_init() override; bool on_init() override;
std::string on_get_name() const override; std::string on_get_name() const override;
void on_set_state() override void on_set_state() override {
{
for (GLGizmoRotate& g : m_gizmos) for (GLGizmoRotate& g : m_gizmos)
g.set_state(m_state); g.set_state(m_state);
} }
void on_set_hover_id() override void on_set_hover_id() override {
{
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); 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) if (id < 3)
m_gizmos[id].enable_grabber(0); 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) if (id < 3)
m_gizmos[id].disable_grabber(0); m_gizmos[id].disable_grabber(0);
} }
bool on_is_activable() const override; bool on_is_activable() const override;
void on_start_dragging() override; void on_start_dragging() override;
void on_stop_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) { for (GLGizmoRotate& g : m_gizmos) {
g.update(data); g.update(data);
} }
} }
void on_render() override; void on_render() override;
void on_render_for_picking() override void on_render_for_picking() override {
{
for (GLGizmoRotate& g : m_gizmos) { for (GLGizmoRotate& g : m_gizmos) {
g.render_for_picking(); g.render_for_picking();
} }
@ -157,10 +161,11 @@ protected:
private: private:
class RotoptimzeWindow { class RotoptimzeWindow
{
ImGuiWrapper *m_imgui = nullptr; ImGuiWrapper *m_imgui = nullptr;
public:
public:
struct State { struct State {
float accuracy = 1.f; float accuracy = 1.f;
int method_id = 0; int method_id = 0;

View file

@ -24,12 +24,16 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan
//BBS: GUI refactor: add obj manipulation //BBS: GUI refactor: add obj manipulation
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id) : 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 //BBS: GUI refactor: add obj manipulation
, m_object_manipulation(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 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<float>(); scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging) 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) 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) 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 || 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) 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"; std::string tooltip = "X: " + format(scale.x(), 2) + "%\n";
tooltip += "Y: " + format(scale(1), 2) + "%\n"; tooltip += "Y: " + format(scale.y(), 2) + "%\n";
tooltip += "Z: " + format(scale(2), 2) + "%"; tooltip += "Z: " + format(scale.z(), 2) + "%";
return tooltip; return tooltip;
} }
else else
@ -71,8 +75,7 @@ void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
bool GLGizmoScale3D::on_init() bool GLGizmoScale3D::on_init()
{ {
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i) {
{
m_grabbers.push_back(Grabber()); m_grabbers.push_back(Grabber());
} }
@ -106,8 +109,7 @@ bool GLGizmoScale3D::on_is_activable() const
void GLGizmoScale3D::on_start_dragging() 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.drag_position = m_grabbers[m_hover_id].center;
m_starting.plane_center = m_grabbers[4].center; m_starting.plane_center = m_grabbers[4].center;
m_starting.plane_nromal = m_grabbers[5].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(); 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(); 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[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min(0), center(1), center(2)); m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z());
m_starting.pivots[2] = m_transform * Vec3d(center(0), m_starting.box.max(1), center(2)); m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z());
m_starting.pivots[3] = m_transform * Vec3d(center(0), m_starting.box.min(1), center(2)); m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
m_starting.pivots[4] = m_transform * Vec3d(center(0), center(1), m_starting.box.max(2)); m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
m_starting.pivots[5] = m_transform * Vec3d(center(0), center(1), m_starting.box.min(2)); m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
} }
} }
void GLGizmoScale3D::on_update(const UpdateData& data) 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); 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); 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); do_scale_along_axis(Z, data);
else if (m_hover_id >= 6) else if (m_hover_id >= 6)
do_scale_uniform(data); 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)); bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
// x axis // x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min(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(0), center(1), m_box.min(2)); m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z());
// y axis // y axis
m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(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(0), m_box.max(1), m_box.min(2)); m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z());
// z axis do not show 4 // 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[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 // uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(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(0), m_box.min(1), m_box.min(2)); 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(0), m_box.max(1), m_box.min(2)); 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(0), m_box.max(1), m_box.min(2)); 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) { for (int i = 0; i < 6; ++i) {
m_grabbers[i].color = AXES_COLOR[i/2]; m_grabbers[i].color = AXES_COLOR[i/2];
@ -228,26 +230,23 @@ void GLGizmoScale3D::on_render()
const BoundingBoxf3& selection_box = selection.get_bounding_box(); 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 //draw connections
GLShaderProgram* shader = wxGetApp().get_shader("flat");
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) if (shader != nullptr) {
//if (single_instance || single_volume) { shader->start_using();
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
if (m_grabbers[4].enabled && m_grabbers[5].enabled) { //if (single_instance || single_volume) {
glsafe(::glColor4fv(m_grabbers[4].color.data())); if (m_grabbers[4].enabled && m_grabbers[5].enabled)
render_grabbers_connection(4, 5); 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 // draw grabbers
render_grabbers(grabber_mean_size); 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()); 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(); auto grabber_connection = [this](unsigned int id_1, unsigned int id_2) {
if ((id_1 < grabbers_count) && (id_2 < grabbers_count)) 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)
glLineStipple(1, 0x0FFF); return i;
glEnable(GL_LINE_STIPPLE); }
::glBegin(GL_LINES); return -1;
::glVertex3dv(m_grabbers[id_1].center.data()); };
::glVertex3dv(m_grabbers[id_2].center.data());
glsafe(::glEnd()); int id = grabber_connection(id_1, id_2);
glDisable(GL_LINE_STIPPLE); 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<float>());
entity.positions.emplace_back(m_grabbers[id_2].center.cast<float>());
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 //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) void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{ {
double ratio = calc_ratio(data); double ratio = calc_ratio(data);
if (ratio > 0.0) if (ratio > 0.0) {
{
m_scale(axis) = m_starting.scale(axis) * ratio; 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); double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis) if (m_hover_id == 2 * axis)
local_offset *= -1.0; 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) void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{ {
double ratio = calc_ratio(data); double ratio = calc_ratio(data);
if (ratio > 0.0) if (ratio > 0.0) {
{
m_scale = m_starting.scale * ratio; m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
} }
@ -322,11 +351,11 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{ {
double ratio = 0.0; 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; Vec3d starting_vec = m_starting.drag_position - pivot;
double len_starting_vec = starting_vec.norm(); 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 mouse_dir = data.mouse_ray.unit_vector();
Vec3d plane_normal = m_starting.plane_nromal; Vec3d plane_normal = m_starting.plane_nromal;
if (m_hover_id == 5) { if (m_hover_id == 5) {

View file

@ -32,10 +32,19 @@ class GLGizmoScale3D : public GLGizmoBase
mutable Transform3d m_transform; mutable Transform3d m_transform;
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes) // Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
mutable Transform3d m_offsets_transform; mutable Transform3d m_offsets_transform;
Vec3d m_scale; Vec3d m_scale{ Vec3d::Ones() };
Vec3d m_offset; Vec3d m_offset{ Vec3d::Zero() };
double m_snap_step; double m_snap_step{ 0.05 };
StartingData m_starting; StartingData m_starting;
struct GrabberConnection
{
GLModel model;
std::pair<unsigned int, unsigned int> grabber_indices;
Vec3d old_v1{ Vec3d::Zero() };
Vec3d old_v2{ Vec3d::Zero() };
};
std::array<GrabberConnection, 7> m_grabber_connections;
//BBS: add size adjust related //BBS: add size adjust related
GizmoObjectManipulation* m_object_manipulation; GizmoObjectManipulation* m_object_manipulation;
@ -68,7 +77,7 @@ protected:
virtual void on_render_input_window(float x, float y, float bottom_limit); virtual void on_render_input_window(float x, float y, float bottom_limit);
private: 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_along_axis(Axis axis, const UpdateData& data);
void do_scale_uniform(const UpdateData& data); void do_scale_uniform(const UpdateData& data);

View file

@ -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(); const Selection& selection = m_parent.get_selection();

View file

@ -10,7 +10,7 @@ class GLGizmoSeam : public GLGizmoPainterBase
public: public:
GLGizmoSeam(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoSeam(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
void render_painter_gizmo() const override; void render_painter_gizmo() override;
//BBS //BBS
bool on_key_down_select_tool_type(int keyCode); bool on_key_down_select_tool_type(int keyCode);

View file

@ -692,7 +692,7 @@ void GLGizmosManager::render_current_gizmo() const
m_gizmos[m_current]->render(); 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 // This function shall only be called when current gizmo is
// derived from GLGizmoPainterBase. // derived from GLGizmoPainterBase.

View file

@ -31,16 +31,24 @@ class CommonGizmosDataPool;
class GizmoObjectManipulation; class GizmoObjectManipulation;
class Rect class Rect
{ {
float m_left; float m_left{ 0.0f };
float m_top; float m_top{ 0.0f };
float m_right; float m_right{ 0.0f };
float m_bottom; float m_bottom{ 0.0f };
public: 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) {} 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; } float get_left() const { return m_left; }
void set_left(float left) { m_left = left; } void set_left(float left) { m_left = left; }
@ -287,7 +295,7 @@ public:
void on_change_color_mode(bool is_dark); void on_change_color_mode(bool is_dark);
void render_current_gizmo() const; void render_current_gizmo() const;
void render_current_gizmo_for_picking_pass() 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_painter_assemble_view() const;
void render_overlay(); void render_overlay();