Merge branch 'gizmos_3d' of https://github.com/prusa3d/Slic3r into dev

This commit is contained in:
Enrico Turri 2018-08-23 09:45:04 +02:00
commit a5fcdeec23
263 changed files with 107595 additions and 693 deletions

View file

@ -202,7 +202,9 @@ const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
GLVolume::GLVolume(float r, float g, float b, float a)
: m_angle_z(0.0f)
, m_scale_factor(1.0f)
, m_dirty(true)
, m_transformed_bounding_box_dirty(true)
, m_transformed_convex_hull_bounding_box_dirty(true)
, m_convex_hull(nullptr)
, composite_id(-1)
, select_group_id(-1)
, drag_group_id(-1)
@ -219,8 +221,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
, tverts_range(0, size_t(-1))
, qverts_range(0, size_t(-1))
{
m_world_mat = std::vector<float>(UNIT_MATRIX, std::end(UNIT_MATRIX));
color[0] = r;
color[1] = g;
color[2] = b;
@ -264,45 +264,76 @@ const Pointf3& GLVolume::get_origin() const
void GLVolume::set_origin(const Pointf3& origin)
{
m_origin = origin;
m_dirty = true;
if (m_origin != origin)
{
m_origin = origin;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
void GLVolume::set_angle_z(float angle_z)
{
m_angle_z = angle_z;
m_dirty = true;
if (m_angle_z != angle_z)
{
m_angle_z = angle_z;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
void GLVolume::set_scale_factor(float scale_factor)
{
m_scale_factor = scale_factor;
m_dirty = true;
if (m_scale_factor != scale_factor)
{
m_scale_factor = scale_factor;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
const std::vector<float>& GLVolume::world_matrix() const
void GLVolume::set_convex_hull(const TriangleMesh& convex_hull)
{
if (m_dirty)
{
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
m.translate(Eigen::Vector3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z));
m.rotate(Eigen::AngleAxisf(m_angle_z, Eigen::Vector3f::UnitZ()));
m.scale(m_scale_factor);
::memcpy((void*)m_world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
m_dirty = false;
}
m_convex_hull = &convex_hull;
}
return m_world_mat;
std::vector<float> GLVolume::world_matrix() const
{
std::vector<float> world_mat(UNIT_MATRIX, std::end(UNIT_MATRIX));
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
m.translate(Eigen::Vector3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z));
m.rotate(Eigen::AngleAxisf(m_angle_z, Eigen::Vector3f::UnitZ()));
m.scale(m_scale_factor);
::memcpy((void*)world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
return world_mat;
}
BoundingBoxf3 GLVolume::transformed_bounding_box() const
{
if (m_dirty)
if (m_transformed_bounding_box_dirty)
{
m_transformed_bounding_box = bounding_box.transformed(world_matrix());
m_transformed_bounding_box_dirty = false;
}
return m_transformed_bounding_box;
}
BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box() const
{
if (m_transformed_convex_hull_bounding_box_dirty)
{
if ((m_convex_hull != nullptr) && (m_convex_hull->stl.stats.number_of_facets > 0))
m_transformed_convex_hull_bounding_box = m_convex_hull->transformed_bounding_box(world_matrix());
else
m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix());
m_transformed_convex_hull_bounding_box_dirty = false;
}
return m_transformed_convex_hull_bounding_box;
}
void GLVolume::set_range(double min_z, double max_z)
{
this->qverts_range.first = 0;
@ -629,6 +660,7 @@ std::vector<int> GLVolumeCollection::load_object(
if (!model_volume->modifier)
{
v.set_convex_hull(model_volume->get_convex_hull());
v.layer_height_texture = layer_height_texture;
if (extruder_id != -1)
v.extruder_id = extruder_id;
@ -801,9 +833,9 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
for (GLVolume* volume : this->volumes)
{
if ((volume != nullptr) && !volume->is_modifier)
if ((volume != nullptr) && !volume->is_modifier && (!volume->is_wipe_tower || (volume->is_wipe_tower && volume->shader_outside_printer_detection_enabled)))
{
const BoundingBoxf3& bb = volume->transformed_bounding_box();
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
bool contained = print_volume.contains(bb);
all_contained &= contained;
@ -1820,6 +1852,11 @@ void _3DScene::enable_gizmos(wxGLCanvas* canvas, bool enable)
s_canvas_mgr.enable_gizmos(canvas, enable);
}
void _3DScene::enable_toolbar(wxGLCanvas* canvas, bool enable)
{
s_canvas_mgr.enable_toolbar(canvas, enable);
}
void _3DScene::enable_shader(wxGLCanvas* canvas, bool enable)
{
s_canvas_mgr.enable_shader(canvas, enable);
@ -1840,6 +1877,16 @@ void _3DScene::allow_multisample(wxGLCanvas* canvas, bool allow)
s_canvas_mgr.allow_multisample(canvas, allow);
}
void _3DScene::enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable)
{
s_canvas_mgr.enable_toolbar_item(canvas, name, enable);
}
bool _3DScene::is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name)
{
return s_canvas_mgr.is_toolbar_item_pressed(canvas, name);
}
void _3DScene::zoom_to_bed(wxGLCanvas* canvas)
{
s_canvas_mgr.zoom_to_bed(canvas);
@ -1975,6 +2022,71 @@ void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, voi
s_canvas_mgr.register_on_update_geometry_info_callback(canvas, callback);
}
void _3DScene::register_action_add_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_add_callback(canvas, callback);
}
void _3DScene::register_action_delete_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_delete_callback(canvas, callback);
}
void _3DScene::register_action_deleteall_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_deleteall_callback(canvas, callback);
}
void _3DScene::register_action_arrange_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_arrange_callback(canvas, callback);
}
void _3DScene::register_action_more_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_more_callback(canvas, callback);
}
void _3DScene::register_action_fewer_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_fewer_callback(canvas, callback);
}
void _3DScene::register_action_ccw45_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_ccw45_callback(canvas, callback);
}
void _3DScene::register_action_cw45_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_cw45_callback(canvas, callback);
}
void _3DScene::register_action_scale_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_scale_callback(canvas, callback);
}
void _3DScene::register_action_split_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_split_callback(canvas, callback);
}
void _3DScene::register_action_cut_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_cut_callback(canvas, callback);
}
void _3DScene::register_action_settings_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_settings_callback(canvas, callback);
}
void _3DScene::register_action_layersediting_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_action_layersediting_callback(canvas, callback);
}
static inline int hex_digit_to_int(const char c)
{
return

View file

@ -260,12 +260,16 @@ private:
float m_angle_z;
// Scale factor of the volume to be rendered.
float m_scale_factor;
// World matrix of the volume to be rendered.
std::vector<float> m_world_mat;
// Bounding box of this volume, in unscaled coordinates.
mutable BoundingBoxf3 m_transformed_bounding_box;
// Whether or not is needed to recalculate the world matrix.
mutable bool m_dirty;
// Whether or not is needed to recalculate the transformed bounding box.
mutable bool m_transformed_bounding_box_dirty;
// Pointer to convex hull of the original mesh, if any.
const TriangleMesh* m_convex_hull;
// Bounding box of this volume, in unscaled coordinates.
mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box;
// Whether or not is needed to recalculate the transformed convex hull bounding box.
mutable bool m_transformed_convex_hull_bounding_box_dirty;
public:
@ -323,13 +327,15 @@ public:
void set_origin(const Pointf3& origin);
void set_angle_z(float angle_z);
void set_scale_factor(float scale_factor);
void set_convex_hull(const TriangleMesh& convex_hull);
int object_idx() const { return this->composite_id / 1000000; }
int volume_idx() const { return (this->composite_id / 1000) % 1000; }
int instance_idx() const { return this->composite_id % 1000; }
const std::vector<float>& world_matrix() const;
std::vector<float> world_matrix() const;
BoundingBoxf3 transformed_bounding_box() const;
BoundingBoxf3 transformed_convex_hull_bounding_box() const;
bool empty() const { return this->indexed_vertex_array.empty(); }
bool indexed() const { return this->indexed_vertex_array.indexed(); }
@ -497,11 +503,15 @@ public:
static void enable_picking(wxGLCanvas* canvas, bool enable);
static void enable_moving(wxGLCanvas* canvas, bool enable);
static void enable_gizmos(wxGLCanvas* canvas, bool enable);
static void enable_toolbar(wxGLCanvas* canvas, bool enable);
static void enable_shader(wxGLCanvas* canvas, bool enable);
static void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable);
static void enable_dynamic_background(wxGLCanvas* canvas, bool enable);
static void allow_multisample(wxGLCanvas* canvas, bool allow);
static void enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable);
static bool is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name);
static void zoom_to_bed(wxGLCanvas* canvas);
static void zoom_to_volumes(wxGLCanvas* canvas);
static void select_view(wxGLCanvas* canvas, const std::string& direction);
@ -534,6 +544,20 @@ public:
static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
static void register_action_add_callback(wxGLCanvas* canvas, void* callback);
static void register_action_delete_callback(wxGLCanvas* canvas, void* callback);
static void register_action_deleteall_callback(wxGLCanvas* canvas, void* callback);
static void register_action_arrange_callback(wxGLCanvas* canvas, void* callback);
static void register_action_more_callback(wxGLCanvas* canvas, void* callback);
static void register_action_fewer_callback(wxGLCanvas* canvas, void* callback);
static void register_action_ccw45_callback(wxGLCanvas* canvas, void* callback);
static void register_action_cw45_callback(wxGLCanvas* canvas, void* callback);
static void register_action_scale_callback(wxGLCanvas* canvas, void* callback);
static void register_action_split_callback(wxGLCanvas* canvas, void* callback);
static void register_action_cut_callback(wxGLCanvas* canvas, void* callback);
static void register_action_settings_callback(wxGLCanvas* canvas, void* callback);
static void register_action_layersediting_callback(wxGLCanvas* canvas, void* callback);
static std::vector<int> load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector<int> instance_idxs);
static std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);

View file

@ -1130,7 +1130,11 @@ GLCanvas3D::Gizmos::~Gizmos()
bool GLCanvas3D::Gizmos::init()
{
#if ENABLE_GIZMOS_3D
GLGizmoBase* gizmo = new GLGizmoScale3D;
#else
GLGizmoBase* gizmo = new GLGizmoScale;
#endif // ENABLE_GIZMOS_3D
if (gizmo == nullptr)
return false;
@ -1139,7 +1143,11 @@ bool GLCanvas3D::Gizmos::init()
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
gizmo = new GLGizmoRotate;
#if ENABLE_GIZMOS_3D
gizmo = new GLGizmoRotate3D;
#else
gizmo = new GLGizmoRotate(GLGizmoRotate::Z);
#endif // ENABLE_GIZMOS_3D
if (gizmo == nullptr)
{
_reset();
@ -1294,14 +1302,14 @@ bool GLCanvas3D::Gizmos::grabber_contains_mouse() const
return (curr != nullptr) ? (curr->get_hover_id() != -1) : false;
}
void GLCanvas3D::Gizmos::update(const Pointf& mouse_pos)
void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray)
{
if (!m_enabled)
return;
GLGizmoBase* curr = _get_current();
if (curr != nullptr)
curr->update(mouse_pos);
curr->update(mouse_ray);
}
void GLCanvas3D::Gizmos::refresh()
@ -1355,7 +1363,11 @@ float GLCanvas3D::Gizmos::get_scale() const
return 1.0f;
GizmosMap::const_iterator it = m_gizmos.find(Scale);
#if ENABLE_GIZMOS_3D
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale3D*>(it->second)->get_scale_x() : 1.0f;
#else
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale*>(it->second)->get_scale() : 1.0f;
#endif // ENABLE_GIZMOS_3D
}
void GLCanvas3D::Gizmos::set_scale(float scale)
@ -1365,7 +1377,11 @@ void GLCanvas3D::Gizmos::set_scale(float scale)
GizmosMap::const_iterator it = m_gizmos.find(Scale);
if (it != m_gizmos.end())
#if ENABLE_GIZMOS_3D
reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale);
#else
reinterpret_cast<GLGizmoScale*>(it->second)->set_scale(scale);
#endif // ENABLE_GIZMOS_3D
}
float GLCanvas3D::Gizmos::get_angle_z() const
@ -1374,7 +1390,11 @@ float GLCanvas3D::Gizmos::get_angle_z() const
return 0.0f;
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate*>(it->second)->get_angle_z() : 0.0f;
#if ENABLE_GIZMOS_3D
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate3D*>(it->second)->get_angle_z() : 0.0f;
#else
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate*>(it->second)->get_angle() : 0.0f;
#endif // ENABLE_GIZMOS_3D
}
void GLCanvas3D::Gizmos::set_angle_z(float angle_z)
@ -1384,25 +1404,20 @@ void GLCanvas3D::Gizmos::set_angle_z(float angle_z)
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoRotate*>(it->second)->set_angle_z(angle_z);
#if ENABLE_GIZMOS_3D
reinterpret_cast<GLGizmoRotate3D*>(it->second)->set_angle_z(angle_z);
#else
reinterpret_cast<GLGizmoRotate*>(it->second)->set_angle(angle_z);
#endif // ENABLE_GIZMOS_3D
}
void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const
void GLCanvas3D::Gizmos::render_current_gizmo(const BoundingBoxf3& box) const
{
if (!m_enabled)
return;
::glDisable(GL_DEPTH_TEST);
if (box.radius() > 0.0)
_render_current_gizmo(box);
::glPushMatrix();
::glLoadIdentity();
_render_overlay(canvas);
::glPopMatrix();
}
void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const
@ -1410,13 +1425,26 @@ void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const BoundingBox
if (!m_enabled)
return;
::glDisable(GL_DEPTH_TEST);
GLGizmoBase* curr = _get_current();
if (curr != nullptr)
curr->render_for_picking(box);
}
void GLCanvas3D::Gizmos::render_overlay(const GLCanvas3D& canvas) const
{
if (!m_enabled)
return;
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
_render_overlay(canvas);
::glPopMatrix();
}
void GLCanvas3D::Gizmos::_reset()
{
for (GizmosMap::value_type& gizmo : m_gizmos)
@ -1473,6 +1501,13 @@ float GLCanvas3D::Gizmos::_get_total_overlay_height() const
const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 };
const unsigned char GLCanvas3D::WarningTexture::Opacity = 255;
GLCanvas3D::WarningTexture::WarningTexture()
: GUI::GLTexture()
, m_original_width(0)
, m_original_height(0)
{
}
bool GLCanvas3D::WarningTexture::generate(const std::string& msg)
{
reset();
@ -1482,13 +1517,21 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg)
wxMemoryDC memDC;
// select default font
memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
font.MakeLarger();
font.MakeBold();
memDC.SetFont(font);
// calculates texture size
wxCoord w, h;
memDC.GetTextExtent(msg, &w, &h);
m_width = (int)w;
m_height = (int)h;
int pow_of_two_size = next_highest_power_of_2((int)std::max(w, h));
m_original_width = (int)w;
m_original_height = (int)h;
m_width = pow_of_two_size;
m_height = pow_of_two_size;
// generates bitmap
wxBitmap bitmap(m_width, m_height);
@ -1540,10 +1583,51 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg)
return true;
}
void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const
{
if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0))
{
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
const Size& cnv_size = canvas.get_canvas_size();
float zoom = canvas.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float left = (-0.5f * (float)m_original_width) * inv_zoom;
float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom;
float right = left + (float)m_original_width * inv_zoom;
float bottom = top - (float)m_original_height * inv_zoom;
float uv_left = 0.0f;
float uv_top = 0.0f;
float uv_right = (float)m_original_width / (float)m_width;
float uv_bottom = (float)m_original_height / (float)m_height;
GLTexture::Quad_UVs uvs;
uvs.left_top = { uv_left, uv_top };
uvs.left_bottom = { uv_left, uv_bottom };
uvs.right_bottom = { uv_right, uv_bottom };
uvs.right_top = { uv_right, uv_top };
GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs);
::glPopMatrix();
::glEnable(GL_DEPTH_TEST);
}
}
const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 };
const unsigned char GLCanvas3D::LegendTexture::Background_Color[3] = { 9, 91, 134 };
const unsigned char GLCanvas3D::LegendTexture::Opacity = 255;
GLCanvas3D::LegendTexture::LegendTexture()
: GUI::GLTexture()
, m_original_width(0)
, m_original_height(0)
{
}
bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
{
reset();
@ -1576,10 +1660,15 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
max_text_height = std::max(max_text_height, (int)h);
}
m_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width);
m_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square;
m_original_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width);
m_original_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square;
if (items_count > 1)
m_height += (items_count - 1) * Px_Square_Contour;
m_original_height += (items_count - 1) * Px_Square_Contour;
int pow_of_two_size = next_highest_power_of_2(std::max(m_original_width, m_original_height));
m_width = pow_of_two_size;
m_height = pow_of_two_size;
// generates bitmap
wxBitmap bitmap(m_width, m_height);
@ -1688,6 +1777,40 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
return true;
}
void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
{
if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0))
{
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
const Size& cnv_size = canvas.get_canvas_size();
float zoom = canvas.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom;
float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom;
float right = left + (float)m_original_width * inv_zoom;
float bottom = top - (float)m_original_height * inv_zoom;
float uv_left = 0.0f;
float uv_top = 0.0f;
float uv_right = (float)m_original_width / (float)m_width;
float uv_bottom = (float)m_original_height / (float)m_height;
GLTexture::Quad_UVs uvs;
uvs.left_top = { uv_left, uv_top };
uvs.left_bottom = { uv_left, uv_bottom };
uvs.right_bottom = { uv_right, uv_bottom };
uvs.right_top = { uv_right, uv_top };
GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs);
::glPopMatrix();
::glEnable(GL_DEPTH_TEST);
}
}
GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const
{
GizmosMap::const_iterator it = m_gizmos.find(m_current);
@ -1698,6 +1821,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
: m_canvas(canvas)
, m_context(nullptr)
, m_timer(nullptr)
, m_toolbar(*this)
, m_config(nullptr)
, m_print(nullptr)
, m_model(nullptr)
@ -1707,6 +1831,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
, m_force_zoom_to_bed_enabled(false)
, m_apply_zoom_to_volumes_filter(false)
, m_hover_volume_id(-1)
, m_toolbar_action_running(false)
, m_warning_texture_enabled(false)
, m_legend_texture_enabled(false)
, m_picking_enabled(false)
@ -1813,6 +1938,9 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl)
if (m_gizmos.is_enabled() && !m_gizmos.init())
return false;
if (!_init_toolbar())
return false;
m_initialized = true;
return true;
@ -2076,6 +2204,11 @@ void GLCanvas3D::enable_gizmos(bool enable)
m_gizmos.set_enabled(enable);
}
void GLCanvas3D::enable_toolbar(bool enable)
{
m_toolbar.set_enabled(enable);
}
void GLCanvas3D::enable_shader(bool enable)
{
m_shader_enabled = enable;
@ -2096,6 +2229,19 @@ void GLCanvas3D::allow_multisample(bool allow)
m_multisample_allowed = allow;
}
void GLCanvas3D::enable_toolbar_item(const std::string& name, bool enable)
{
if (enable)
m_toolbar.enable_item(name);
else
m_toolbar.disable_item(name);
}
bool GLCanvas3D::is_toolbar_item_pressed(const std::string& name) const
{
return m_toolbar.is_item_pressed(name);
}
void GLCanvas3D::zoom_to_bed()
{
_zoom_to_bounding_box(m_bed.get_bounding_box());
@ -2207,6 +2353,9 @@ void GLCanvas3D::render()
_picking_pass();
_render_background();
_render_current_gizmo();
// untextured bed needs to be rendered before objects
if (is_custom_bed)
{
@ -2215,6 +2364,7 @@ void GLCanvas3D::render()
_render_axes(false);
}
_render_objects();
// textured bed needs to be rendered after objects
if (!is_custom_bed)
{
@ -2222,9 +2372,10 @@ void GLCanvas3D::render()
_render_bed(theta);
}
_render_cutting_plane();
_render_gizmos_overlay();
_render_warning_texture();
_render_legend_texture();
_render_gizmo();
_render_toolbar();
_render_layer_editing_overlay();
m_canvas->SwapBuffers();
@ -2527,6 +2678,84 @@ void GLCanvas3D::register_on_update_geometry_info_callback(void* callback)
m_on_update_geometry_info_callback.register_callback(callback);
}
void GLCanvas3D::register_action_add_callback(void* callback)
{
if (callback != nullptr)
m_action_add_callback.register_callback(callback);
}
void GLCanvas3D::register_action_delete_callback(void* callback)
{
if (callback != nullptr)
m_action_delete_callback.register_callback(callback);
}
void GLCanvas3D::register_action_deleteall_callback(void* callback)
{
if (callback != nullptr)
m_action_deleteall_callback.register_callback(callback);
}
void GLCanvas3D::register_action_arrange_callback(void* callback)
{
if (callback != nullptr)
m_action_arrange_callback.register_callback(callback);
}
void GLCanvas3D::register_action_more_callback(void* callback)
{
if (callback != nullptr)
m_action_more_callback.register_callback(callback);
}
void GLCanvas3D::register_action_fewer_callback(void* callback)
{
if (callback != nullptr)
m_action_fewer_callback.register_callback(callback);
}
void GLCanvas3D::register_action_ccw45_callback(void* callback)
{
if (callback != nullptr)
m_action_ccw45_callback.register_callback(callback);
}
void GLCanvas3D::register_action_cw45_callback(void* callback)
{
if (callback != nullptr)
m_action_cw45_callback.register_callback(callback);
}
void GLCanvas3D::register_action_scale_callback(void* callback)
{
if (callback != nullptr)
m_action_scale_callback.register_callback(callback);
}
void GLCanvas3D::register_action_split_callback(void* callback)
{
if (callback != nullptr)
m_action_split_callback.register_callback(callback);
}
void GLCanvas3D::register_action_cut_callback(void* callback)
{
if (callback != nullptr)
m_action_cut_callback.register_callback(callback);
}
void GLCanvas3D::register_action_settings_callback(void* callback)
{
if (callback != nullptr)
m_action_settings_callback.register_callback(callback);
}
void GLCanvas3D::register_action_layersediting_callback(void* callback)
{
if (callback != nullptr)
m_action_layersediting_callback.register_callback(callback);
}
void GLCanvas3D::bind_event_handlers()
{
if (m_canvas != nullptr)
@ -2704,6 +2933,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1;
m_layers_editing.last_object_id = layer_editing_object_idx;
bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position);
int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position);
if (evt.Entering())
{
@ -2723,6 +2953,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
else if (evt.LeftDClick() && (m_hover_volume_id != -1))
m_on_double_click_callback.call();
else if (evt.LeftDClick() && (toolbar_contains_mouse != -1))
{
m_toolbar_action_running = true;
m_toolbar.do_action((unsigned int)toolbar_contains_mouse);
}
else if (evt.LeftDown() || evt.RightDown())
{
// If user pressed left or right button we first check whether this happened
@ -2761,6 +2996,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx);
m_dirty = true;
}
else if (toolbar_contains_mouse != -1)
{
m_toolbar_action_running = true;
m_toolbar.do_action((unsigned int)toolbar_contains_mouse);
}
else
{
// Select volume in this 3D canvas.
@ -2817,9 +3057,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
else if (evt.RightDown())
{
// if right clicking on volume, propagate event through callback
if (m_volumes.volumes[volume_idx]->hover)
m_on_right_click_callback.call(pos.x, pos.y);
// forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while
// the context menu is already shown, ensuring it to disappear if the mouse is outside any volume
m_mouse.position = Pointf((coordf_t)pos.x, (coordf_t)pos.y);
render();
if (m_hover_volume_id != -1)
{
// if right clicking on volume, propagate event through callback (shows context menu)
if (m_volumes.volumes[volume_idx]->hover)
m_on_right_click_callback.call(pos.x, pos.y);
}
}
}
}
@ -2881,9 +3128,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.Dragging() && m_gizmos.is_dragging())
{
m_mouse.dragging = true;
const Pointf3& cur_pos = _mouse_to_bed_3d(pos);
m_gizmos.update(Pointf(cur_pos.x, cur_pos.y));
m_gizmos.update(mouse_ray(pos));
std::vector<GLVolume*> volumes;
if (m_mouse.drag.gizmo_volume_idx != -1)
@ -3017,11 +3262,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
_on_move(volume_idxs);
// force re-selection of the wipe tower, if needed
if ((volume_idxs.size() == 1) && m_volumes.volumes[volume_idxs[0]]->is_wipe_tower)
select_volume(volume_idxs[0]);
}
else if (!m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled())
else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled())
{
// deselect and propagate event through callback
if (m_picking_enabled)
if (m_picking_enabled && !m_toolbar_action_running)
{
deselect_volumes();
_on_select(-1);
@ -3053,6 +3302,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.set_start_position_3D_as_invalid();
m_mouse.set_start_position_2D_as_invalid();
m_mouse.dragging = false;
m_toolbar_action_running = false;
m_dirty = true;
}
else if (evt.Moving())
@ -3119,6 +3369,12 @@ void GLCanvas3D::reset_legend_texture()
m_legend_texture.reset();
}
void GLCanvas3D::set_tooltip(const std::string& tooltip)
{
if (m_canvas != nullptr)
m_canvas->SetToolTip(tooltip);
}
bool GLCanvas3D::_is_shown_on_screen() const
{
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
@ -3130,6 +3386,143 @@ void GLCanvas3D::_force_zoom_to_bed()
m_force_zoom_to_bed_enabled = false;
}
bool GLCanvas3D::_init_toolbar()
{
if (!m_toolbar.is_enabled())
return true;
if (!m_toolbar.init("toolbar.png", 36, 1, 1))
{
// unable to init the toolbar texture, disable it
m_toolbar.set_enabled(false);
return true;
}
// m_toolbar.set_layout_type(GLToolbar::Layout::Vertical);
m_toolbar.set_layout_type(GLToolbar::Layout::Horizontal);
m_toolbar.set_separator_size(5);
m_toolbar.set_gap_size(2);
GLToolbarItem::Data item;
item.name = "add";
item.tooltip = GUI::L_str("Add...");
item.sprite_id = 0;
item.is_toggable = false;
item.action_callback = &m_action_add_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "delete";
item.tooltip = GUI::L_str("Delete");
item.sprite_id = 1;
item.is_toggable = false;
item.action_callback = &m_action_delete_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "deleteall";
item.tooltip = GUI::L_str("Delete all");
item.sprite_id = 2;
item.is_toggable = false;
item.action_callback = &m_action_deleteall_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "arrange";
item.tooltip = GUI::L_str("Arrange");
item.sprite_id = 3;
item.is_toggable = false;
item.action_callback = &m_action_arrange_callback;
if (!m_toolbar.add_item(item))
return false;
if (!m_toolbar.add_separator())
return false;
item.name = "more";
item.tooltip = GUI::L_str("Add instance");
item.sprite_id = 4;
item.is_toggable = false;
item.action_callback = &m_action_more_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "fewer";
item.tooltip = GUI::L_str("Remove instance");
item.sprite_id = 5;
item.is_toggable = false;
item.action_callback = &m_action_fewer_callback;
if (!m_toolbar.add_item(item))
return false;
if (!m_toolbar.add_separator())
return false;
item.name = "ccw45";
item.tooltip = GUI::L_str("Rotate CCW 45 degrees");
item.sprite_id = 6;
item.is_toggable = false;
item.action_callback = &m_action_ccw45_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "cw45";
item.tooltip = GUI::L_str("Rotate CW 45 degrees");
item.sprite_id = 7;
item.is_toggable = false;
item.action_callback = &m_action_cw45_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "scale";
item.tooltip = GUI::L_str("Scale...");
item.sprite_id = 8;
item.is_toggable = false;
item.action_callback = &m_action_scale_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "split";
item.tooltip = GUI::L_str("Split");
item.sprite_id = 9;
item.is_toggable = false;
item.action_callback = &m_action_split_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "cut";
item.tooltip = GUI::L_str("Cut...");
item.sprite_id = 10;
item.is_toggable = false;
item.action_callback = &m_action_cut_callback;
if (!m_toolbar.add_item(item))
return false;
if (!m_toolbar.add_separator())
return false;
item.name = "settings";
item.tooltip = GUI::L_str("Settings...");
item.sprite_id = 11;
item.is_toggable = false;
item.action_callback = &m_action_settings_callback;
if (!m_toolbar.add_item(item))
return false;
item.name = "layersediting";
item.tooltip = GUI::L_str("Layers editing");
item.sprite_id = 12;
item.is_toggable = true;
item.action_callback = &m_action_layersediting_callback;
if (!m_toolbar.add_item(item))
return false;
enable_toolbar_item("add", true);
return true;
}
void GLCanvas3D::_resize(unsigned int w, unsigned int h)
{
if ((m_canvas == nullptr) && (m_context == nullptr))
@ -3243,7 +3636,7 @@ BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const
{
for (const GLVolume* volume : selected_volumes)
{
bb.merge(volume->transformed_bounding_box());
bb.merge(volume->transformed_convex_hull_bounding_box());
}
}
@ -3353,6 +3746,20 @@ void GLCanvas3D::_deregister_callbacks()
m_on_gizmo_scale_uniformly_callback.deregister_callback();
m_on_gizmo_rotate_callback.deregister_callback();
m_on_update_geometry_info_callback.deregister_callback();
m_action_add_callback.deregister_callback();
m_action_delete_callback.deregister_callback();
m_action_deleteall_callback.deregister_callback();
m_action_arrange_callback.deregister_callback();
m_action_more_callback.deregister_callback();
m_action_fewer_callback.deregister_callback();
m_action_ccw45_callback.deregister_callback();
m_action_cw45_callback.deregister_callback();
m_action_scale_callback.deregister_callback();
m_action_split_callback.deregister_callback();
m_action_cut_callback.deregister_callback();
m_action_settings_callback.deregister_callback();
m_action_layersediting_callback.deregister_callback();
}
void GLCanvas3D::_mark_volumes_for_layer_height() const
@ -3417,8 +3824,8 @@ void GLCanvas3D::_picking_pass() const
::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_render_volumes(true);
m_gizmos.render_current_gizmo_for_picking_pass(_selected_volumes_bounding_box());
_render_volumes(true);
if (m_multisample_allowed)
::glEnable(GL_MULTISAMPLE);
@ -3464,6 +3871,8 @@ void GLCanvas3D::_picking_pass() const
m_gizmos.update_hover_state(*this, pos);
else
m_gizmos.reset_all_states();
m_toolbar.update_hover_state(pos);
}
}
@ -3517,6 +3926,7 @@ void GLCanvas3D::_render_objects() const
return;
::glEnable(GL_LIGHTING);
::glEnable(GL_DEPTH_TEST);
if (!m_shader_enabled)
_render_volumes(false);
@ -3568,32 +3978,7 @@ void GLCanvas3D::_render_warning_texture() const
if (!m_warning_texture_enabled)
return;
// If the warning texture has not been loaded into the GPU, do it now.
unsigned int tex_id = m_warning_texture.get_id();
if (tex_id > 0)
{
int w = m_warning_texture.get_width();
int h = m_warning_texture.get_height();
if ((w > 0) && (h > 0))
{
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
const Size& cnv_size = get_canvas_size();
float zoom = get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float l = (-0.5f * (float)w) * inv_zoom;
float t = (-0.5f * (float)cnv_size.get_height() + (float)h) * inv_zoom;
float r = l + (float)w * inv_zoom;
float b = t - (float)h * inv_zoom;
GLTexture::render_texture(tex_id, l, r, b, t);
::glPopMatrix();
::glEnable(GL_DEPTH_TEST);
}
}
m_warning_texture.render(*this);
}
void GLCanvas3D::_render_legend_texture() const
@ -3601,32 +3986,7 @@ void GLCanvas3D::_render_legend_texture() const
if (!m_legend_texture_enabled)
return;
// If the legend texture has not been loaded into the GPU, do it now.
unsigned int tex_id = m_legend_texture.get_id();
if (tex_id > 0)
{
int w = m_legend_texture.get_width();
int h = m_legend_texture.get_height();
if ((w > 0) && (h > 0))
{
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
const Size& cnv_size = get_canvas_size();
float zoom = get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float l = (-0.5f * (float)cnv_size.get_width()) * inv_zoom;
float t = (0.5f * (float)cnv_size.get_height()) * inv_zoom;
float r = l + (float)w * inv_zoom;
float b = t - (float)h * inv_zoom;
GLTexture::render_texture(tex_id, l, r, b, t);
::glPopMatrix();
::glEnable(GL_DEPTH_TEST);
}
}
m_legend_texture.render(*this);
}
void GLCanvas3D::_render_layer_editing_overlay() const
@ -3708,9 +4068,20 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const
::glDisable(GL_LIGHTING);
}
void GLCanvas3D::_render_gizmo() const
void GLCanvas3D::_render_current_gizmo() const
{
m_gizmos.render(*this, _selected_volumes_bounding_box());
m_gizmos.render_current_gizmo(_selected_volumes_bounding_box());
}
void GLCanvas3D::_render_gizmos_overlay() const
{
m_gizmos.render_overlay(*this);
}
void GLCanvas3D::_render_toolbar() const
{
_resize_toolbar();
m_toolbar.render();
}
float GLCanvas3D::_get_layers_editing_cursor_z_relative() const
@ -3793,10 +4164,15 @@ Pointf3 GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
}
Pointf3 GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos)
{
return mouse_ray(mouse_pos).intersect_plane(0.0);
}
Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos)
{
float z0 = 0.0f;
float z1 = 1.0f;
return Linef3(_mouse_to_3d(mouse_pos, &z0), _mouse_to_3d(mouse_pos, &z1)).intersect_plane(0.0);
return Linef3(_mouse_to_3d(mouse_pos, &z0), _mouse_to_3d(mouse_pos, &z1));
}
void GLCanvas3D::_start_timer()
@ -4964,5 +5340,36 @@ bool GLCanvas3D::_is_any_volume_outside() const
return false;
}
void GLCanvas3D::_resize_toolbar() const
{
Size cnv_size = get_canvas_size();
float zoom = get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
switch (m_toolbar.get_layout_type())
{
default:
case GLToolbar::Layout::Horizontal:
{
// centers the toolbar on the top edge of the 3d scene
unsigned int toolbar_width = m_toolbar.get_width();
float top = (0.5f * (float)cnv_size.get_height() - 2.0f) * inv_zoom;
float left = -0.5f * (float)toolbar_width * inv_zoom;
m_toolbar.set_position(top, left);
break;
}
case GLToolbar::Layout::Vertical:
{
// centers the toolbar on the right edge of the 3d scene
unsigned int toolbar_width = m_toolbar.get_width();
unsigned int toolbar_height = m_toolbar.get_height();
float top = 0.5f * (float)toolbar_height * inv_zoom;
float left = (0.5f * (float)cnv_size.get_width() - toolbar_width - 2.0f) * inv_zoom;
m_toolbar.set_position(top, left);
break;
}
}
}
} // namespace GUI
} // namespace Slic3r

View file

@ -2,7 +2,7 @@
#define slic3r_GLCanvas3D_hpp_
#include "../../slic3r/GUI/3DScene.hpp"
#include "../../slic3r/GUI/GLTexture.hpp"
#include "../../slic3r/GUI/GLToolbar.hpp"
class wxTimer;
class wxSizeEvent;
@ -365,7 +365,7 @@ public:
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const;
bool grabber_contains_mouse() const;
void update(const Pointf& mouse_pos);
void update(const Linef3& mouse_ray);
void refresh();
EType get_current_type() const;
@ -382,8 +382,9 @@ public:
float get_angle_z() const;
void set_angle_z(float angle_z);
void render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const;
void render_current_gizmo(const BoundingBoxf3& box) const;
void render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const;
void render_overlay(const GLCanvas3D& canvas) const;
private:
void _reset();
@ -400,8 +401,15 @@ public:
static const unsigned char Background_Color[3];
static const unsigned char Opacity;
int m_original_width;
int m_original_height;
public:
WarningTexture();
bool generate(const std::string& msg);
void render(const GLCanvas3D& canvas) const;
};
class LegendTexture : public GUI::GLTexture
@ -415,8 +423,15 @@ public:
static const unsigned char Background_Color[3];
static const unsigned char Opacity;
int m_original_width;
int m_original_height;
public:
LegendTexture();
bool generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
void render(const GLCanvas3D& canvas) const;
};
private:
@ -433,6 +448,7 @@ private:
Shader m_shader;
Mouse m_mouse;
mutable Gizmos m_gizmos;
mutable GLToolbar m_toolbar;
mutable GLVolumeCollection m_volumes;
DynamicPrintConfig* m_config;
@ -445,6 +461,7 @@ private:
bool m_force_zoom_to_bed_enabled;
bool m_apply_zoom_to_volumes_filter;
mutable int m_hover_volume_id;
bool m_toolbar_action_running;
bool m_warning_texture_enabled;
bool m_legend_texture_enabled;
bool m_picking_enabled;
@ -482,6 +499,20 @@ private:
PerlCallback m_on_gizmo_rotate_callback;
PerlCallback m_on_update_geometry_info_callback;
PerlCallback m_action_add_callback;
PerlCallback m_action_delete_callback;
PerlCallback m_action_deleteall_callback;
PerlCallback m_action_arrange_callback;
PerlCallback m_action_more_callback;
PerlCallback m_action_fewer_callback;
PerlCallback m_action_ccw45_callback;
PerlCallback m_action_cw45_callback;
PerlCallback m_action_scale_callback;
PerlCallback m_action_split_callback;
PerlCallback m_action_cut_callback;
PerlCallback m_action_settings_callback;
PerlCallback m_action_layersediting_callback;
public:
GLCanvas3D(wxGLCanvas* canvas);
~GLCanvas3D();
@ -539,11 +570,15 @@ public:
void enable_picking(bool enable);
void enable_moving(bool enable);
void enable_gizmos(bool enable);
void enable_toolbar(bool enable);
void enable_shader(bool enable);
void enable_force_zoom_to_bed(bool enable);
void enable_dynamic_background(bool enable);
void allow_multisample(bool allow);
void enable_toolbar_item(const std::string& name, bool enable);
bool is_toolbar_item_pressed(const std::string& name) const;
void zoom_to_bed();
void zoom_to_volumes();
void select_view(const std::string& direction);
@ -584,6 +619,20 @@ public:
void register_on_gizmo_rotate_callback(void* callback);
void register_on_update_geometry_info_callback(void* callback);
void register_action_add_callback(void* callback);
void register_action_delete_callback(void* callback);
void register_action_deleteall_callback(void* callback);
void register_action_arrange_callback(void* callback);
void register_action_more_callback(void* callback);
void register_action_fewer_callback(void* callback);
void register_action_ccw45_callback(void* callback);
void register_action_cw45_callback(void* callback);
void register_action_scale_callback(void* callback);
void register_action_split_callback(void* callback);
void register_action_cut_callback(void* callback);
void register_action_settings_callback(void* callback);
void register_action_layersediting_callback(void* callback);
void bind_event_handlers();
void unbind_event_handlers();
@ -601,10 +650,14 @@ public:
void reset_legend_texture();
void set_tooltip(const std::string& tooltip);
private:
bool _is_shown_on_screen() const;
void _force_zoom_to_bed();
bool _init_toolbar();
void _resize(unsigned int w, unsigned int h);
BoundingBoxf3 _max_bounding_box() const;
@ -629,7 +682,9 @@ private:
void _render_legend_texture() const;
void _render_layer_editing_overlay() const;
void _render_volumes(bool fake_colors) const;
void _render_gizmo() const;
void _render_current_gizmo() const;
void _render_gizmos_overlay() const;
void _render_toolbar() const;
float _get_layers_editing_cursor_z_relative() const;
void _perform_layer_editing_action(wxMouseEvent* evt = nullptr);
@ -641,6 +696,9 @@ private:
// Convert the screen space coordinate to world coordinate on the bed.
Pointf3 _mouse_to_bed_3d(const Point& mouse_pos);
// Returns the view ray line, in world coordinate, at the given mouse position.
Linef3 mouse_ray(const Point& mouse_pos);
void _start_timer();
void _stop_timer();
@ -687,6 +745,8 @@ private:
bool _is_any_volume_outside() const;
void _resize_toolbar() const;
static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
};

View file

@ -404,6 +404,13 @@ void GLCanvas3DManager::enable_gizmos(wxGLCanvas* canvas, bool enable)
it->second->enable_gizmos(enable);
}
void GLCanvas3DManager::enable_toolbar(wxGLCanvas* canvas, bool enable)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->enable_toolbar(enable);
}
void GLCanvas3DManager::enable_shader(wxGLCanvas* canvas, bool enable)
{
CanvasesMap::iterator it = _get_canvas(canvas);
@ -432,6 +439,19 @@ void GLCanvas3DManager::allow_multisample(wxGLCanvas* canvas, bool allow)
it->second->allow_multisample(allow);
}
void GLCanvas3DManager::enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->enable_toolbar_item(name, enable);
}
bool GLCanvas3DManager::is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name) const
{
CanvasesMap::const_iterator it = _get_canvas(canvas);
return (it != m_canvases.end()) ? it->second->is_toolbar_item_pressed(name) : false;
}
void GLCanvas3DManager::zoom_to_bed(wxGLCanvas* canvas)
{
CanvasesMap::iterator it = _get_canvas(canvas);
@ -675,6 +695,97 @@ void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* ca
it->second->register_on_update_geometry_info_callback(callback);
}
void GLCanvas3DManager::register_action_add_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_add_callback(callback);
}
void GLCanvas3DManager::register_action_delete_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_delete_callback(callback);
}
void GLCanvas3DManager::register_action_deleteall_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_deleteall_callback(callback);
}
void GLCanvas3DManager::register_action_arrange_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_arrange_callback(callback);
}
void GLCanvas3DManager::register_action_more_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_more_callback(callback);
}
void GLCanvas3DManager::register_action_fewer_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_fewer_callback(callback);
}
void GLCanvas3DManager::register_action_ccw45_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_ccw45_callback(callback);
}
void GLCanvas3DManager::register_action_cw45_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_cw45_callback(callback);
}
void GLCanvas3DManager::register_action_scale_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_scale_callback(callback);
}
void GLCanvas3DManager::register_action_split_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_split_callback(callback);
}
void GLCanvas3DManager::register_action_cut_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_cut_callback(callback);
}
void GLCanvas3DManager::register_action_settings_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_settings_callback(callback);
}
void GLCanvas3DManager::register_action_layersediting_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_action_layersediting_callback(callback);
}
GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas)
{
return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas);

View file

@ -110,11 +110,15 @@ public:
void enable_picking(wxGLCanvas* canvas, bool enable);
void enable_moving(wxGLCanvas* canvas, bool enable);
void enable_gizmos(wxGLCanvas* canvas, bool enable);
void enable_toolbar(wxGLCanvas* canvas, bool enable);
void enable_shader(wxGLCanvas* canvas, bool enable);
void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable);
void enable_dynamic_background(wxGLCanvas* canvas, bool enable);
void allow_multisample(wxGLCanvas* canvas, bool allow);
void enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable);
bool is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name) const;
void zoom_to_bed(wxGLCanvas* canvas);
void zoom_to_volumes(wxGLCanvas* canvas);
void select_view(wxGLCanvas* canvas, const std::string& direction);
@ -157,6 +161,20 @@ public:
void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
void register_action_add_callback(wxGLCanvas* canvas, void* callback);
void register_action_delete_callback(wxGLCanvas* canvas, void* callback);
void register_action_deleteall_callback(wxGLCanvas* canvas, void* callback);
void register_action_arrange_callback(wxGLCanvas* canvas, void* callback);
void register_action_more_callback(wxGLCanvas* canvas, void* callback);
void register_action_fewer_callback(wxGLCanvas* canvas, void* callback);
void register_action_ccw45_callback(wxGLCanvas* canvas, void* callback);
void register_action_cw45_callback(wxGLCanvas* canvas, void* callback);
void register_action_scale_callback(wxGLCanvas* canvas, void* callback);
void register_action_split_callback(wxGLCanvas* canvas, void* callback);
void register_action_cut_callback(wxGLCanvas* canvas, void* callback);
void register_action_settings_callback(wxGLCanvas* canvas, void* callback);
void register_action_layersediting_callback(wxGLCanvas* canvas, void* callback);
private:
CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas);
CanvasesMap::const_iterator _get_canvas(wxGLCanvas* canvas) const;

File diff suppressed because it is too large Load diff

View file

@ -3,33 +3,53 @@
#include "../../slic3r/GUI/GLTexture.hpp"
#include "../../libslic3r/Point.hpp"
#include "../../libslic3r/BoundingBox.hpp"
#include <vector>
#define ENABLE_GIZMOS_3D 1
namespace Slic3r {
class BoundingBoxf3;
class Pointf3;
class Linef3;
namespace GUI {
class GLGizmoBase
{
protected:
static const float BaseColor[3];
static const float HighlightColor[3];
struct Grabber
{
static const float HalfSize;
static const float HoverOffset;
static const float DraggingScaleFactor;
Pointf center;
Pointf3 center;
float angle_x;
float angle_y;
float angle_z;
float color[3];
bool dragging;
Grabber();
void render(bool hover) const;
#if ENABLE_GIZMOS_3D
void render_for_picking() const { render(color, false); }
#else
void render_for_picking() const { render(color); }
#endif // ENABLE_GIZMOS_3D
private:
#if ENABLE_GIZMOS_3D
void render(const float* render_color, bool use_lighting) const;
#else
void render(const float* render_color) const;
#endif // ENABLE_GIZMOS_3D
#if ENABLE_GIZMOS_3D
void render_face(float half_size) const;
#endif // ENABLE_GIZMOS_3D
};
public:
@ -42,46 +62,59 @@ public:
};
protected:
int m_group_id;
EState m_state;
// textures are assumed to be square and all with the same size in pixels, no internal check is done
GLTexture m_textures[Num_States];
int m_hover_id;
float m_base_color[3];
float m_drag_color[3];
float m_highlight_color[3];
mutable std::vector<Grabber> m_grabbers;
bool m_is_container;
public:
GLGizmoBase();
virtual ~GLGizmoBase();
virtual ~GLGizmoBase() {}
bool init();
bool init() { return on_init(); }
EState get_state() const;
void set_state(EState state);
int get_group_id() const { return m_group_id; }
void set_group_id(int id) { m_group_id = id; }
unsigned int get_texture_id() const;
int get_textures_size() const;
EState get_state() const { return m_state; }
void set_state(EState state) { m_state = state; on_set_state(); }
int get_hover_id() const;
unsigned int get_texture_id() const { return m_textures[m_state].get_id(); }
int get_textures_size() const { return m_textures[Off].get_width(); }
int get_hover_id() const { return m_hover_id; }
void set_hover_id(int id);
void set_highlight_color(const float* color);
void start_dragging();
void stop_dragging();
void update(const Pointf& mouse_pos);
void refresh();
void update(const Linef3& mouse_ray);
void refresh() { on_refresh(); }
void render(const BoundingBoxf3& box) const;
void render_for_picking(const BoundingBoxf3& box) const;
void render(const BoundingBoxf3& box) const { on_render(box); }
void render_for_picking(const BoundingBoxf3& box) const { on_render_for_picking(box); }
protected:
virtual bool on_init() = 0;
virtual void on_set_state();
virtual void on_start_dragging();
virtual void on_stop_dragging();
virtual void on_update(const Pointf& mouse_pos) = 0;
virtual void on_refresh();
virtual void on_set_state() {}
virtual void on_set_hover_id() {}
virtual void on_start_dragging() {}
virtual void on_stop_dragging() {}
virtual void on_update(const Linef3& mouse_ray) = 0;
virtual void on_refresh() {}
virtual void on_render(const BoundingBoxf3& box) const = 0;
virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0;
float picking_color_component(unsigned int id) const;
void render_grabbers() const;
void render_grabbers_for_picking() const;
};
class GLGizmoRotate : public GLGizmoBase
@ -97,33 +130,101 @@ class GLGizmoRotate : public GLGizmoBase
static const unsigned int SnapRegionsCount;
static const float GrabberOffset;
float m_angle_z;
public:
enum Axis : unsigned char
{
X,
Y,
Z
};
mutable Pointf m_center;
private:
Axis m_axis;
float m_angle;
mutable Pointf3 m_center;
mutable float m_radius;
mutable bool m_keep_radius;
mutable bool m_keep_initial_values;
public:
GLGizmoRotate();
explicit GLGizmoRotate(Axis axis);
float get_angle_z() const;
void set_angle_z(float angle_z);
float get_angle() const { return m_angle; }
void set_angle(float angle);
protected:
virtual bool on_init();
virtual void on_set_state();
virtual void on_update(const Pointf& mouse_pos);
virtual void on_refresh();
virtual void on_set_state() { m_keep_initial_values = (m_state == On) ? false : true; }
virtual void on_update(const Linef3& mouse_ray);
virtual void on_refresh() { m_keep_initial_values = false; }
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
private:
void _render_circle() const;
void _render_scale() const;
void _render_snap_radii() const;
void _render_reference_radius() const;
void _render_angle_z() const;
void _render_grabber() const;
void render_circle() const;
void render_scale() const;
void render_snap_radii() const;
void render_reference_radius() const;
void render_angle() const;
void render_grabber() const;
void transform_to_local() const;
Pointf mouse_position_in_local_plane(const Linef3& mouse_ray) const;
};
class GLGizmoRotate3D : public GLGizmoBase
{
GLGizmoRotate m_x;
GLGizmoRotate m_y;
GLGizmoRotate m_z;
public:
GLGizmoRotate3D();
float get_angle_x() const { return m_x.get_angle(); }
void set_angle_x(float angle) { m_x.set_angle(angle); }
float get_angle_y() const { return m_y.get_angle(); }
void set_angle_y(float angle) { m_y.set_angle(angle); }
float get_angle_z() const { return m_z.get_angle(); }
void set_angle_z(float angle) { m_z.set_angle(angle); }
protected:
virtual bool on_init();
virtual void on_set_state()
{
m_x.set_state(m_state);
m_y.set_state(m_state);
m_z.set_state(m_state);
}
virtual void on_set_hover_id()
{
m_x.set_hover_id(m_hover_id == 0 ? 0 : -1);
m_y.set_hover_id(m_hover_id == 1 ? 0 : -1);
m_z.set_hover_id(m_hover_id == 2 ? 0 : -1);
}
virtual void on_start_dragging();
virtual void on_stop_dragging();
virtual void on_update(const Linef3& mouse_ray)
{
m_x.update(mouse_ray);
m_y.update(mouse_ray);
m_z.update(mouse_ray);
}
virtual void on_refresh()
{
m_x.refresh();
m_y.refresh();
m_z.refresh();
}
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const
{
m_x.render_for_picking(box);
m_y.render_for_picking(box);
m_z.render_for_picking(box);
}
};
class GLGizmoScale : public GLGizmoBase
@ -138,17 +239,72 @@ class GLGizmoScale : public GLGizmoBase
public:
GLGizmoScale();
float get_scale() const;
void set_scale(float scale);
float get_scale() const { return m_scale; }
void set_scale(float scale) { m_starting_scale = scale; }
protected:
virtual bool on_init();
virtual void on_start_dragging();
virtual void on_update(const Pointf& mouse_pos);
virtual void on_update(const Linef3& mouse_ray);
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
};
class GLGizmoScale3D : public GLGizmoBase
{
static const float Offset;
mutable BoundingBoxf3 m_box;
float m_scale_x;
float m_scale_y;
float m_scale_z;
float m_starting_scale_x;
float m_starting_scale_y;
float m_starting_scale_z;
Pointf3 m_starting_drag_position;
Pointf3 m_starting_center;
public:
GLGizmoScale3D();
float get_scale_x() const { return m_scale_x; }
void set_scale_x(float scale) { m_starting_scale_x = scale; }
float get_scale_y() const { return m_scale_y; }
void set_scale_y(float scale) { m_starting_scale_y = scale; }
float get_scale_z() const { return m_scale_z; }
void set_scale_z(float scale) { m_starting_scale_z = scale; }
void set_scale(float scale)
{
m_starting_scale_x = scale;
m_starting_scale_y = scale;
m_starting_scale_z = scale;
}
protected:
virtual bool on_init();
virtual void on_start_dragging();
virtual void on_update(const Linef3& mouse_ray);
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
private:
void render_box() const;
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
void do_scale_x(const Linef3& mouse_ray);
void do_scale_y(const Linef3& mouse_ray);
void do_scale_z(const Linef3& mouse_ray);
void do_scale_uniform(const Linef3& mouse_ray);
double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Pointf3& center) const;
};
} // namespace GUI
} // namespace Slic3r

View file

@ -12,6 +12,8 @@
namespace Slic3r {
namespace GUI {
GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } };
GLTexture::GLTexture()
: m_id(0)
, m_width(0)
@ -128,6 +130,11 @@ const std::string& GLTexture::get_source() const
}
void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top)
{
render_sub_texture(tex_id, left, right, bottom, top, FullTextureUVs);
}
void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const GLTexture::Quad_UVs& uvs)
{
::glEnable(GL_BLEND);
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -138,10 +145,10 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo
::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id);
::glBegin(GL_QUADS);
::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom);
::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(right, bottom);
::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top);
::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(left, top);
::glTexCoord2f(uvs.left_bottom.u, uvs.left_bottom.v); ::glVertex2f(left, bottom);
::glTexCoord2f(uvs.right_bottom.u, uvs.right_bottom.v); ::glVertex2f(right, bottom);
::glTexCoord2f(uvs.right_top.u, uvs.right_top.v); ::glVertex2f(right, top);
::glTexCoord2f(uvs.left_top.u, uvs.left_top.v); ::glVertex2f(left, top);
::glEnd();
::glBindTexture(GL_TEXTURE_2D, 0);

View file

@ -10,6 +10,23 @@ namespace GUI {
class GLTexture
{
public:
struct UV
{
float u;
float v;
};
struct Quad_UVs
{
UV left_bottom;
UV right_bottom;
UV right_top;
UV left_top;
};
static Quad_UVs FullTextureUVs;
protected:
unsigned int m_id;
int m_width;
@ -30,6 +47,7 @@ namespace GUI {
const std::string& get_source() const;
static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top);
static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs);
protected:
unsigned int _generate_mipmaps(wxImage& image);

View file

@ -0,0 +1,721 @@
#include "GLToolbar.hpp"
#include "../../slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <wx/bitmap.h>
#include <wx/dcmemory.h>
#include <wx/settings.h>
namespace Slic3r {
namespace GUI {
GLToolbarItem::Data::Data()
: name("")
, tooltip("")
, sprite_id(-1)
, is_toggable(false)
, action_callback(nullptr)
{
}
GLToolbarItem::GLToolbarItem(GLToolbarItem::EType type, const GLToolbarItem::Data& data)
: m_type(type)
, m_state(Disabled)
, m_data(data)
{
}
GLToolbarItem::EState GLToolbarItem::get_state() const
{
return m_state;
}
void GLToolbarItem::set_state(GLToolbarItem::EState state)
{
m_state = state;
}
const std::string& GLToolbarItem::get_name() const
{
return m_data.name;
}
const std::string& GLToolbarItem::get_tooltip() const
{
return m_data.tooltip;
}
void GLToolbarItem::do_action()
{
if (m_data.action_callback != nullptr)
m_data.action_callback->call();
}
bool GLToolbarItem::is_enabled() const
{
return m_state != Disabled;
}
bool GLToolbarItem::is_hovered() const
{
return (m_state == Hover) || (m_state == HoverPressed);
}
bool GLToolbarItem::is_pressed() const
{
return (m_state == Pressed) || (m_state == HoverPressed);
}
bool GLToolbarItem::is_toggable() const
{
return m_data.is_toggable;
}
bool GLToolbarItem::is_separator() const
{
return m_type == Separator;
}
void GLToolbarItem::render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const
{
GLTexture::render_sub_texture(tex_id, left, right, bottom, top, _get_uvs(texture_size, border_size, icon_size, gap_size));
}
GLTexture::Quad_UVs GLToolbarItem::_get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const
{
GLTexture::Quad_UVs uvs;
float inv_texture_size = (texture_size != 0) ? 1.0f / (float)texture_size : 0.0f;
float scaled_icon_size = (float)icon_size * inv_texture_size;
float scaled_border_size = (float)border_size * inv_texture_size;
float scaled_gap_size = (float)gap_size * inv_texture_size;
float stride = scaled_icon_size + scaled_gap_size;
float left = scaled_border_size + (float)m_state * stride;
float right = left + scaled_icon_size;
float top = scaled_border_size + (float)m_data.sprite_id * stride;
float bottom = top + scaled_icon_size;
uvs.left_top = { left, top };
uvs.left_bottom = { left, bottom };
uvs.right_bottom = { right, bottom };
uvs.right_top = { right, top };
return uvs;
}
GLToolbar::ItemsIconsTexture::ItemsIconsTexture()
: items_icon_size(0)
, items_icon_border_size(0)
, items_icon_gap_size(0)
{
}
GLToolbar::Layout::Layout()
: type(Horizontal)
, top(0.0f)
, left(0.0f)
, separator_size(0.0f)
, gap_size(0.0f)
{
}
GLToolbar::GLToolbar(GLCanvas3D& parent)
: m_parent(parent)
, m_enabled(false)
{
}
bool GLToolbar::init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size)
{
std::string path = resources_dir() + "/icons/";
bool res = !icons_texture_filename.empty() && m_icons_texture.texture.load_from_file(path + icons_texture_filename, false);
if (res)
{
m_icons_texture.items_icon_size = items_icon_size;
m_icons_texture.items_icon_border_size = items_icon_border_size;
m_icons_texture.items_icon_gap_size = items_icon_gap_size;
}
return res;
}
GLToolbar::Layout::Type GLToolbar::get_layout_type() const
{
return m_layout.type;
}
void GLToolbar::set_layout_type(GLToolbar::Layout::Type type)
{
m_layout.type = type;
}
void GLToolbar::set_position(float top, float left)
{
m_layout.top = top;
m_layout.left = left;
}
void GLToolbar::set_separator_size(float size)
{
m_layout.separator_size = size;
}
void GLToolbar::set_gap_size(float size)
{
m_layout.gap_size = size;
}
bool GLToolbar::is_enabled() const
{
return m_enabled;
}
void GLToolbar::set_enabled(bool enable)
{
m_enabled = true;
}
bool GLToolbar::add_item(const GLToolbarItem::Data& data)
{
GLToolbarItem* item = new GLToolbarItem(GLToolbarItem::Action, data);
if (item == nullptr)
return false;
m_items.push_back(item);
return true;
}
bool GLToolbar::add_separator()
{
GLToolbarItem::Data data;
GLToolbarItem* item = new GLToolbarItem(GLToolbarItem::Separator, data);
if (item == nullptr)
return false;
m_items.push_back(item);
return true;
}
float GLToolbar::get_width() const
{
switch (m_layout.type)
{
default:
case Layout::Horizontal:
{
return _get_width_horizontal();
}
case Layout::Vertical:
{
return _get_width_vertical();
}
}
}
float GLToolbar::get_height() const
{
switch (m_layout.type)
{
default:
case Layout::Horizontal:
{
return _get_height_horizontal();
}
case Layout::Vertical:
{
return _get_height_vertical();
}
}
}
void GLToolbar::enable_item(const std::string& name)
{
for (GLToolbarItem* item : m_items)
{
if ((item->get_name() == name) && (item->get_state() == GLToolbarItem::Disabled))
{
item->set_state(GLToolbarItem::Normal);
return;
}
}
}
void GLToolbar::disable_item(const std::string& name)
{
for (GLToolbarItem* item : m_items)
{
if (item->get_name() == name)
{
item->set_state(GLToolbarItem::Disabled);
return;
}
}
}
bool GLToolbar::is_item_pressed(const std::string& name) const
{
for (GLToolbarItem* item : m_items)
{
if (item->get_name() == name)
return item->is_pressed();
}
return false;
}
void GLToolbar::update_hover_state(const Pointf& mouse_pos)
{
if (!m_enabled)
return;
switch (m_layout.type)
{
default:
case Layout::Horizontal:
{
_update_hover_state_horizontal(mouse_pos);
break;
}
case Layout::Vertical:
{
_update_hover_state_vertical(mouse_pos);
break;
}
}
}
int GLToolbar::contains_mouse(const Pointf& mouse_pos) const
{
if (!m_enabled)
return -1;
switch (m_layout.type)
{
default:
case Layout::Horizontal:
{
return _contains_mouse_horizontal(mouse_pos);
}
case Layout::Vertical:
{
return _contains_mouse_vertical(mouse_pos);
}
}
}
void GLToolbar::do_action(unsigned int item_id)
{
if (item_id < (unsigned int)m_items.size())
{
GLToolbarItem* item = m_items[item_id];
if ((item != nullptr) && !item->is_separator() && item->is_hovered())
{
if (item->is_toggable())
{
GLToolbarItem::EState state = item->get_state();
if (state == GLToolbarItem::Hover)
item->set_state(GLToolbarItem::HoverPressed);
else if (state == GLToolbarItem::HoverPressed)
item->set_state(GLToolbarItem::Hover);
m_parent.render();
item->do_action();
}
else
{
item->set_state(GLToolbarItem::HoverPressed);
m_parent.render();
item->do_action();
if (item->get_state() != GLToolbarItem::Disabled)
{
// the item may get disabled during the action, if not, set it back to hover state
item->set_state(GLToolbarItem::Hover);
m_parent.render();
}
}
}
}
}
void GLToolbar::render() const
//void GLToolbar::render(const Pointf& mouse_pos) const
{
if (!m_enabled || m_items.empty())
return;
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
switch (m_layout.type)
{
default:
case Layout::Horizontal:
{
_render_horizontal();
break;
}
case Layout::Vertical:
{
_render_vertical();
break;
}
}
::glPopMatrix();
}
float GLToolbar::_get_width_horizontal() const
{
return _get_main_size();
}
float GLToolbar::_get_width_vertical() const
{
return m_icons_texture.items_icon_size;
}
float GLToolbar::_get_height_horizontal() const
{
return m_icons_texture.items_icon_size;
}
float GLToolbar::_get_height_vertical() const
{
return _get_main_size();
}
float GLToolbar::_get_main_size() const
{
float size = 0.0f;
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
{
if (m_items[i]->is_separator())
size += m_layout.separator_size;
else
size += (float)m_icons_texture.items_icon_size;
}
if (m_items.size() > 1)
size += ((float)m_items.size() - 1.0f) * m_layout.gap_size;
return size;
}
void GLToolbar::_update_hover_state_horizontal(const Pointf& mouse_pos)
{
float zoom = m_parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size();
Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
float scaled_separator_size = m_layout.separator_size * inv_zoom;
float scaled_gap_size = m_layout.gap_size * inv_zoom;
float separator_stride = scaled_separator_size + scaled_gap_size;
float icon_stride = scaled_icons_size + scaled_gap_size;
float left = m_layout.left;
float top = m_layout.top;
std::string tooltip = "";
for (GLToolbarItem* item : m_items)
{
if (item->is_separator())
left += separator_stride;
else
{
float right = left + scaled_icons_size;
float bottom = top - scaled_icons_size;
GLToolbarItem::EState state = item->get_state();
bool inside = (left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top);
switch (state)
{
case GLToolbarItem::Normal:
{
if (inside)
item->set_state(GLToolbarItem::Hover);
break;
}
case GLToolbarItem::Hover:
{
if (inside)
tooltip = item->get_tooltip();
else
item->set_state(GLToolbarItem::Normal);
break;
}
case GLToolbarItem::Pressed:
{
if (inside)
item->set_state(GLToolbarItem::HoverPressed);
break;
}
case GLToolbarItem::HoverPressed:
{
if (inside)
tooltip = item->get_tooltip();
else
item->set_state(GLToolbarItem::Pressed);
break;
}
default:
case GLToolbarItem::Disabled:
{
break;
}
}
left += icon_stride;
}
}
m_parent.set_tooltip(tooltip);
}
void GLToolbar::_update_hover_state_vertical(const Pointf& mouse_pos)
{
float zoom = m_parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size();
Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
float scaled_separator_size = m_layout.separator_size * inv_zoom;
float scaled_gap_size = m_layout.gap_size * inv_zoom;
float separator_stride = scaled_separator_size + scaled_gap_size;
float icon_stride = scaled_icons_size + scaled_gap_size;
float left = m_layout.left;
float top = m_layout.top;
std::string tooltip = "";
for (GLToolbarItem* item : m_items)
{
if (item->is_separator())
top -= separator_stride;
else
{
float right = left + scaled_icons_size;
float bottom = top - scaled_icons_size;
GLToolbarItem::EState state = item->get_state();
bool inside = (left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top);
switch (state)
{
case GLToolbarItem::Normal:
{
if (inside)
item->set_state(GLToolbarItem::Hover);
break;
}
case GLToolbarItem::Hover:
{
if (inside)
tooltip = item->get_tooltip();
else
item->set_state(GLToolbarItem::Normal);
break;
}
case GLToolbarItem::Pressed:
{
if (inside)
item->set_state(GLToolbarItem::HoverPressed);
break;
}
case GLToolbarItem::HoverPressed:
{
if (inside)
tooltip = item->get_tooltip();
else
item->set_state(GLToolbarItem::Pressed);
break;
}
default:
case GLToolbarItem::Disabled:
{
break;
}
}
top -= icon_stride;
}
}
m_parent.set_tooltip(tooltip);
}
int GLToolbar::_contains_mouse_horizontal(const Pointf& mouse_pos) const
{
float zoom = m_parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size();
Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
float scaled_separator_size = m_layout.separator_size * inv_zoom;
float scaled_gap_size = m_layout.gap_size * inv_zoom;
float separator_stride = scaled_separator_size + scaled_gap_size;
float icon_stride = scaled_icons_size + scaled_gap_size;
float left = m_layout.left;
float top = m_layout.top;
int id = -1;
for (GLToolbarItem* item : m_items)
{
++id;
if (item->is_separator())
left += separator_stride;
else
{
float right = left + scaled_icons_size;
float bottom = top - scaled_icons_size;
if ((left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top))
return id;
left += icon_stride;
}
}
return -1;
}
int GLToolbar::_contains_mouse_vertical(const Pointf& mouse_pos) const
{
float zoom = m_parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size();
Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
float scaled_separator_size = m_layout.separator_size * inv_zoom;
float scaled_gap_size = m_layout.gap_size * inv_zoom;
float separator_stride = scaled_separator_size + scaled_gap_size;
float icon_stride = scaled_icons_size + scaled_gap_size;
float left = m_layout.left;
float top = m_layout.top;
int id = -1;
for (GLToolbarItem* item : m_items)
{
++id;
if (item->is_separator())
top -= separator_stride;
else
{
float right = left + scaled_icons_size;
float bottom = top - scaled_icons_size;
if ((left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top))
return id;
top -= icon_stride;
}
}
return -1;
}
void GLToolbar::_render_horizontal() const
{
unsigned int tex_id = m_icons_texture.texture.get_id();
int tex_size = m_icons_texture.texture.get_width();
if ((tex_id == 0) || (tex_size <= 0))
return;
float zoom = m_parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
float scaled_separator_size = m_layout.separator_size * inv_zoom;
float scaled_gap_size = m_layout.gap_size * inv_zoom;
float separator_stride = scaled_separator_size + scaled_gap_size;
float icon_stride = scaled_icons_size + scaled_gap_size;
float left = m_layout.left;
float top = m_layout.top;
// renders icons
for (const GLToolbarItem* item : m_items)
{
if (item->is_separator())
left += separator_stride;
else
{
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.items_icon_border_size, m_icons_texture.items_icon_size, m_icons_texture.items_icon_gap_size);
left += icon_stride;
}
}
}
void GLToolbar::_render_vertical() const
{
unsigned int tex_id = m_icons_texture.texture.get_id();
int tex_size = m_icons_texture.texture.get_width();
if ((tex_id == 0) || (tex_size <= 0))
return;
float zoom = m_parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
float scaled_separator_size = m_layout.separator_size * inv_zoom;
float scaled_gap_size = m_layout.gap_size * inv_zoom;
float separator_stride = scaled_separator_size + scaled_gap_size;
float icon_stride = scaled_icons_size + scaled_gap_size;
float left = m_layout.left;
float top = m_layout.top;
// renders icons
for (const GLToolbarItem* item : m_items)
{
if (item->is_separator())
top -= separator_stride;
else
{
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.items_icon_border_size, m_icons_texture.items_icon_size, m_icons_texture.items_icon_gap_size);
top -= icon_stride;
}
}
}
} // namespace GUI
} // namespace Slic3r

View file

@ -0,0 +1,177 @@
#ifndef slic3r_GLToolbar_hpp_
#define slic3r_GLToolbar_hpp_
#include "../../slic3r/GUI/GLTexture.hpp"
#include "../../libslic3r/Utils.hpp"
#include <string>
#include <vector>
namespace Slic3r {
class Pointf;
namespace GUI {
class GLCanvas3D;
class GLToolbarItem
{
public:
enum EType : unsigned char
{
Action,
Separator,
Num_Types
};
enum EState : unsigned char
{
Normal,
Pressed,
Disabled,
Hover,
HoverPressed,
Num_States
};
struct Data
{
std::string name;
std::string tooltip;
unsigned int sprite_id;
bool is_toggable;
PerlCallback* action_callback;
Data();
};
private:
EType m_type;
EState m_state;
Data m_data;
public:
GLToolbarItem(EType type, const Data& data);
EState get_state() const;
void set_state(EState state);
const std::string& get_name() const;
const std::string& get_tooltip() const;
void do_action();
bool is_enabled() const;
bool is_hovered() const;
bool is_pressed() const;
bool is_toggable() const;
bool is_separator() const;
void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const;
private:
GLTexture::Quad_UVs _get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const;
};
class GLToolbar
{
public:
// items icon textures are assumed to be square and all with the same size in pixels, no internal check is done
// icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState
// from left to right
struct ItemsIconsTexture
{
GLTexture texture;
// size of the square icons, in pixels
unsigned int items_icon_size;
// distance from the border, in pixels
unsigned int items_icon_border_size;
// distance between two adjacent icons (to avoid filtering artifacts), in pixels
unsigned int items_icon_gap_size;
ItemsIconsTexture();
};
struct Layout
{
enum Type : unsigned char
{
Horizontal,
Vertical,
Num_Types
};
Type type;
float top;
float left;
float separator_size;
float gap_size;
Layout();
};
private:
typedef std::vector<GLToolbarItem*> ItemsList;
GLCanvas3D& m_parent;
bool m_enabled;
ItemsIconsTexture m_icons_texture;
Layout m_layout;
ItemsList m_items;
public:
explicit GLToolbar(GLCanvas3D& parent);
bool init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size);
Layout::Type get_layout_type() const;
void set_layout_type(Layout::Type type);
void set_position(float top, float left);
void set_separator_size(float size);
void set_gap_size(float size);
bool is_enabled() const;
void set_enabled(bool enable);
bool add_item(const GLToolbarItem::Data& data);
bool add_separator();
float get_width() const;
float get_height() const;
void enable_item(const std::string& name);
void disable_item(const std::string& name);
bool is_item_pressed(const std::string& name) const;
void update_hover_state(const Pointf& mouse_pos);
// returns the id of the item under the given mouse position or -1 if none
int contains_mouse(const Pointf& mouse_pos) const;
void do_action(unsigned int item_id);
void render() const;
private:
float _get_width_horizontal() const;
float _get_width_vertical() const;
float _get_height_horizontal() const;
float _get_height_vertical() const;
float _get_main_size() const;
void _update_hover_state_horizontal(const Pointf& mouse_pos);
void _update_hover_state_vertical(const Pointf& mouse_pos);
int _contains_mouse_horizontal(const Pointf& mouse_pos) const;
int _contains_mouse_vertical(const Pointf& mouse_pos) const;
void _render_horizontal() const;
void _render_vertical() const;
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GLToolbar_hpp_