mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-25 07:34:03 -06:00
Merge branch 'master' of https://github.com/prusa3d/Slic3r
This commit is contained in:
commit
b0ecf07e9b
47 changed files with 1832 additions and 507 deletions
|
@ -59,6 +59,11 @@ void AppConfig::set_defaults()
|
|||
if (get("use_legacy_opengl").empty())
|
||||
set("use_legacy_opengl", "0");
|
||||
|
||||
#if __APPLE__
|
||||
if (get("use_retina_opengl").empty())
|
||||
set("use_retina_opengl", "1");
|
||||
#endif
|
||||
|
||||
if (get("remember_output_path").empty())
|
||||
set("remember_output_path", "1");
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "libslic3r/GCode/PreviewData.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/Technologies.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "slic3r/GUI/BackgroundSlicingProcess.hpp"
|
||||
#include "slic3r/GUI/GLShader.hpp"
|
||||
|
@ -20,6 +21,10 @@
|
|||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
#include "slic3r/Utils/RetinaHelper.hpp"
|
||||
#endif
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
@ -45,6 +50,7 @@
|
|||
#include <iostream>
|
||||
#include <float.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
static const float TRACKBALLSIZE = 0.8f;
|
||||
static const float GIMBALL_LOCK_THETA_MAX = 180.0f;
|
||||
|
@ -59,8 +65,6 @@ static const float VIEW_BOTTOM[2] = { 0.0f, 180.0f };
|
|||
static const float VIEW_FRONT[2] = { 0.0f, 90.0f };
|
||||
static const float VIEW_REAR[2] = { 180.0f, 90.0f };
|
||||
|
||||
static const float VARIABLE_LAYER_THICKNESS_BAR_WIDTH = 70.0f;
|
||||
static const float VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
|
||||
static const float GIZMO_RESET_BUTTON_HEIGHT = 22.0f;
|
||||
static const float GIZMO_RESET_BUTTON_WIDTH = 70.f;
|
||||
|
||||
|
@ -191,9 +195,10 @@ Size::Size()
|
|||
{
|
||||
}
|
||||
|
||||
Size::Size(int width, int height)
|
||||
Size::Size(int width, int height, float scale_factor)
|
||||
: m_width(width)
|
||||
, m_height(height)
|
||||
, m_scale_factor(scale_factor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -217,6 +222,16 @@ void Size::set_height(int height)
|
|||
m_height = height;
|
||||
}
|
||||
|
||||
int Size::get_scale_factor() const
|
||||
{
|
||||
return m_scale_factor;
|
||||
}
|
||||
|
||||
void Size::set_scale_factor(int scale_factor)
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
}
|
||||
|
||||
Rect::Rect()
|
||||
: m_left(0.0f)
|
||||
, m_top(0.0f)
|
||||
|
@ -330,6 +345,7 @@ void GLCanvas3D::Camera::set_scene_box(const BoundingBoxf3& box, GLCanvas3D& can
|
|||
|
||||
GLCanvas3D::Bed::Bed()
|
||||
: m_type(Custom)
|
||||
, m_scale_factor(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -392,8 +408,10 @@ Point GLCanvas3D::Bed::point_projection(const Point& point) const
|
|||
}
|
||||
|
||||
#if ENABLE_PRINT_BED_MODELS
|
||||
void GLCanvas3D::Bed::render(float theta, bool useVBOs) const
|
||||
void GLCanvas3D::Bed::render(float theta, bool useVBOs, float scale_factor) const
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case MK2:
|
||||
|
@ -420,8 +438,10 @@ void GLCanvas3D::Bed::render(float theta, bool useVBOs) const
|
|||
}
|
||||
}
|
||||
#else
|
||||
void GLCanvas3D::Bed::render(float theta) const
|
||||
void GLCanvas3D::Bed::render(float theta, float scale_factor) const
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case MK2:
|
||||
|
@ -675,7 +695,7 @@ void GLCanvas3D::Bed::_render_custom() const
|
|||
|
||||
// we need depth test for grid, otherwise it would disappear when looking the object from below
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
::glLineWidth(3.0f);
|
||||
::glLineWidth(3.0f * m_scale_factor);
|
||||
::glColor4f(0.2f, 0.2f, 0.2f, 0.4f);
|
||||
::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices());
|
||||
::glDrawArrays(GL_LINES, 0, (GLsizei)gridlines_vcount);
|
||||
|
@ -873,6 +893,9 @@ GLCanvas3D::LayersEditing::~LayersEditing()
|
|||
delete m_slicing_parameters;
|
||||
}
|
||||
|
||||
const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f;
|
||||
const float GLCanvas3D::LayersEditing::THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
|
||||
|
||||
bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
|
||||
{
|
||||
if (!m_shader.init(vertex_shader_filename, fragment_shader_filename))
|
||||
|
@ -993,7 +1016,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
|
|||
float w = (float)cnv_size.get_width();
|
||||
float h = (float)cnv_size.get_height();
|
||||
|
||||
return Rect(w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH, 0.0f, w, h - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT);
|
||||
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h - reset_button_height(canvas));
|
||||
}
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas)
|
||||
|
@ -1002,7 +1025,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas)
|
|||
float w = (float)cnv_size.get_width();
|
||||
float h = (float)cnv_size.get_height();
|
||||
|
||||
return Rect(w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH, h - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT, w, h);
|
||||
return Rect(w - thickness_bar_width(canvas), h - reset_button_height(canvas), w, h);
|
||||
}
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
|
||||
|
@ -1014,7 +1037,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
|
|||
float zoom = canvas.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
return Rect((half_w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT) * inv_zoom);
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom);
|
||||
}
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas)
|
||||
|
@ -1026,7 +1049,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas
|
|||
float zoom = canvas.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
return Rect((half_w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH) * inv_zoom, (-half_h + VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1037,6 +1060,8 @@ bool GLCanvas3D::LayersEditing::_is_initialized() const
|
|||
|
||||
void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const
|
||||
{
|
||||
// TODO: do this with ImGui
|
||||
|
||||
if (m_tooltip_texture.get_id() == 0)
|
||||
{
|
||||
std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png";
|
||||
|
@ -1044,6 +1069,15 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas
|
|||
return;
|
||||
}
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
const float scale = canvas.get_canvas_size().get_scale_factor();
|
||||
const float width = (float)m_tooltip_texture.get_width() * scale;
|
||||
const float height = (float)m_tooltip_texture.get_height() * scale;
|
||||
#else
|
||||
const float width = (float)m_tooltip_texture.get_width();
|
||||
const float height = (float)m_tooltip_texture.get_height();
|
||||
#endif
|
||||
|
||||
float zoom = canvas.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float gap = 10.0f * inv_zoom;
|
||||
|
@ -1051,9 +1085,9 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas
|
|||
float bar_left = bar_rect.get_left();
|
||||
float reset_bottom = reset_rect.get_bottom();
|
||||
|
||||
float l = bar_left - (float)m_tooltip_texture.get_width() * inv_zoom - gap;
|
||||
float l = bar_left - width * inv_zoom - gap;
|
||||
float r = bar_left - gap;
|
||||
float t = reset_bottom + (float)m_tooltip_texture.get_height() * inv_zoom + gap;
|
||||
float t = reset_bottom + height * inv_zoom + gap;
|
||||
float b = reset_bottom + gap;
|
||||
|
||||
GLTexture::render_texture(m_tooltip_texture.get_id(), l, r, b, t);
|
||||
|
@ -1082,11 +1116,6 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
|
|||
// The shader requires the original model coordinates when rendering to the texture, so we pass it the unit matrix
|
||||
m_shader.set_uniform("volume_world_matrix", UNIT_MATRIX);
|
||||
|
||||
GLsizei w = (GLsizei)m_layers_texture.width;
|
||||
GLsizei h = (GLsizei)m_layers_texture.height;
|
||||
GLsizei half_w = w / 2;
|
||||
GLsizei half_h = h / 2;
|
||||
|
||||
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
::glBindTexture(GL_TEXTURE_2D, m_z_texture_id);
|
||||
|
||||
|
@ -1267,6 +1296,25 @@ void GLCanvas3D::LayersEditing::update_slicing_parameters()
|
|||
}
|
||||
}
|
||||
|
||||
float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas)
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
return canvas.get_canvas_size().get_scale_factor() * THICKNESS_BAR_WIDTH;
|
||||
#else
|
||||
return THICKNESS_BAR_WIDTH;
|
||||
#endif
|
||||
}
|
||||
|
||||
float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas)
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
return canvas.get_canvas_size().get_scale_factor() * THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
#else
|
||||
return THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
|
||||
const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
#if ENABLE_MOVE_MIN_THRESHOLD
|
||||
|
@ -1329,6 +1377,7 @@ GLCanvas3D::Selection::Selection()
|
|||
, m_valid(false)
|
||||
, m_bounding_box_dirty(true)
|
||||
, m_curved_arrow(16)
|
||||
, m_scale_factor(1.0f)
|
||||
{
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
m_quadric = ::gluNewQuadric();
|
||||
|
@ -1721,7 +1770,7 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local)
|
|||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
_synchronize_unselected_instances();
|
||||
_synchronize_unselected_instances(SYNC_ROTATION_NONE);
|
||||
else if (m_mode == Volume)
|
||||
_synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
@ -1729,64 +1778,100 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local)
|
|||
m_bounding_box_dirty = true;
|
||||
}
|
||||
|
||||
static Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||
{
|
||||
return
|
||||
// From the current coordinate system to world.
|
||||
Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) *
|
||||
// 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());
|
||||
}
|
||||
|
||||
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
|
||||
static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||
{
|
||||
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
|
||||
Vec3d axis = angle_axis.axis();
|
||||
double angle = angle_axis.angle();
|
||||
#ifdef _DEBUG
|
||||
if (std::abs(angle) > 1e-8) {
|
||||
assert(std::abs(axis.x()) < 1e-8);
|
||||
assert(std::abs(axis.y()) < 1e-8);
|
||||
}
|
||||
#endif /* _DEBUG */
|
||||
return (axis.z() < 0) ? -angle : angle;
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
int rot_axis_max;
|
||||
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
||||
|
||||
// For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
|
||||
std::vector<int> object_instance_first(m_model->objects.size(), -1);
|
||||
auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) {
|
||||
int first_volume_idx = object_instance_first[volume.object_idx()];
|
||||
if (rot_axis_max != 2 && first_volume_idx != -1) {
|
||||
// Generic rotation, but no rotation around the Z axis.
|
||||
// Always do a local rotation (do not consider the selection to be a rigid body).
|
||||
assert(rotation.z() == 0);
|
||||
const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
|
||||
const Vec3d &rotation = first_volume.get_instance_rotation();
|
||||
double z_diff = rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
|
||||
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
|
||||
} else {
|
||||
// extracts rotations from the composed transformation
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix());
|
||||
if (rot_axis_max == 2 && !local)
|
||||
// Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
|
||||
volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
volume.set_instance_rotation(new_rotation);
|
||||
object_instance_first[volume.object_idx()] = i;
|
||||
}
|
||||
};
|
||||
|
||||
for (unsigned int i : m_list)
|
||||
{
|
||||
GLVolume &volume = *(*m_volumes)[i];
|
||||
if (is_single_full_instance())
|
||||
{
|
||||
if (local)
|
||||
(*m_volumes)[i]->set_instance_rotation(rotation);
|
||||
else
|
||||
{
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix());
|
||||
(*m_volumes)[i]->set_instance_rotation(new_rotation);
|
||||
}
|
||||
}
|
||||
rotate_instance(volume, i);
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
if (local)
|
||||
(*m_volumes)[i]->set_volume_rotation(rotation);
|
||||
volume.set_volume_rotation(rotation);
|
||||
else
|
||||
{
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||
(*m_volumes)[i]->set_volume_rotation(new_rotation);
|
||||
volume.set_volume_rotation(new_rotation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
if (m_mode == Instance)
|
||||
{
|
||||
// extracts rotations from the composed transformation
|
||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix());
|
||||
if (!local)
|
||||
(*m_volumes)[i]->set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
|
||||
(*m_volumes)[i]->set_instance_rotation(new_rotation);
|
||||
}
|
||||
rotate_instance(volume, i);
|
||||
else if (m_mode == Volume)
|
||||
{
|
||||
// extracts rotations from the composed transformation
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||
if (!local)
|
||||
{
|
||||
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
|
||||
(*m_volumes)[i]->set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
||||
volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
||||
}
|
||||
(*m_volumes)[i]->set_volume_rotation(new_rotation);
|
||||
volume.set_volume_rotation(new_rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
_synchronize_unselected_instances();
|
||||
_synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL);
|
||||
else if (m_mode == Volume)
|
||||
_synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
@ -1829,7 +1914,7 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal)
|
|||
// we want to synchronize z-rotation as well, otherwise the flattening behaves funny
|
||||
// when applied on one of several identical instances
|
||||
if (m_mode == Instance)
|
||||
_synchronize_unselected_instances(true);
|
||||
_synchronize_unselected_instances(SYNC_ROTATION_FULL);
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
m_bounding_box_dirty = true;
|
||||
|
@ -1876,7 +1961,7 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale, bool local)
|
|||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
_synchronize_unselected_instances();
|
||||
_synchronize_unselected_instances(SYNC_ROTATION_NONE);
|
||||
else if (m_mode == Volume)
|
||||
_synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
@ -1903,7 +1988,7 @@ void GLCanvas3D::Selection::mirror(Axis axis)
|
|||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
_synchronize_unselected_instances();
|
||||
_synchronize_unselected_instances(SYNC_ROTATION_NONE);
|
||||
else if (m_mode == Volume)
|
||||
_synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
@ -2115,11 +2200,13 @@ void GLCanvas3D::Selection::erase()
|
|||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::render() const
|
||||
void GLCanvas3D::Selection::render(float scale_factor) const
|
||||
{
|
||||
if (!m_valid || is_empty())
|
||||
return;
|
||||
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
// render cumulative bounding box of selected volumes
|
||||
_render_selected_volumes();
|
||||
_render_synchronized_volumes();
|
||||
|
@ -2564,7 +2651,7 @@ void GLCanvas3D::Selection::_render_bounding_box(const BoundingBoxf3& box, float
|
|||
::glEnable(GL_DEPTH_TEST);
|
||||
|
||||
::glColor3fv(color);
|
||||
::glLineWidth(2.0f);
|
||||
::glLineWidth(2.0f * m_scale_factor);
|
||||
|
||||
::glBegin(GL_LINES);
|
||||
|
||||
|
@ -2699,7 +2786,43 @@ void GLCanvas3D::Selection::_render_sidebar_size_hint(Axis axis, double length)
|
|||
{
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z)
|
||||
#ifdef _DEBUG
|
||||
static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||
{
|
||||
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
|
||||
Vec3d axis = angle_axis.axis();
|
||||
double angle = angle_axis.angle();
|
||||
if (std::abs(angle) < 1e-8)
|
||||
return true;
|
||||
assert(std::abs(axis.x()) < 1e-8);
|
||||
assert(std::abs(axis.y()) < 1e-8);
|
||||
assert(std::abs(std::abs(axis.z()) - 1.) < 1e-8);
|
||||
return std::abs(axis.x()) < 1e-8 && std::abs(axis.y()) < 1e-8 && std::abs(std::abs(axis.z()) - 1.) < 1e-8;
|
||||
}
|
||||
static void verify_instances_rotation_synchronized(const Model &model, const GLVolumePtrs &volumes)
|
||||
{
|
||||
for (size_t idx_object = 0; idx_object < model.objects.size(); ++ idx_object) {
|
||||
int idx_volume_first = -1;
|
||||
for (int i = 0; i < (int)volumes.size(); ++ i) {
|
||||
if (volumes[i]->object_idx() == idx_object) {
|
||||
idx_volume_first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(idx_volume_first != -1); // object without instances?
|
||||
if (idx_volume_first == -1)
|
||||
continue;
|
||||
const Vec3d &rotation0 = volumes[idx_volume_first]->get_instance_rotation();
|
||||
for (int i = idx_volume_first + 1; i < (int)volumes.size(); ++ i)
|
||||
if (volumes[i]->object_idx() == idx_object) {
|
||||
const Vec3d &rotation = volumes[i]->get_instance_rotation();
|
||||
assert(is_rotation_xy_synchronized(rotation, rotation0));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _DEBUG */
|
||||
|
||||
void GLCanvas3D::Selection::_synchronize_unselected_instances(SyncRotationType sync_rotation_type)
|
||||
{
|
||||
std::set<unsigned int> done; // prevent processing volumes twice
|
||||
done.insert(m_list.begin(), m_list.end());
|
||||
|
@ -2715,7 +2838,7 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z)
|
|||
continue;
|
||||
|
||||
int instance_idx = volume->instance_idx();
|
||||
const Vec3d& rotation = volume->get_instance_rotation();
|
||||
const Vec3d& rotation = volume->get_instance_rotation();
|
||||
const Vec3d& scaling_factor = volume->get_instance_scaling_factor();
|
||||
const Vec3d& mirror = volume->get_instance_mirror();
|
||||
|
||||
|
@ -2732,26 +2855,34 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z)
|
|||
if ((v->object_idx() != object_idx) || (v->instance_idx() == instance_idx))
|
||||
continue;
|
||||
|
||||
auto is_approx = [](double value, double test_value) -> bool { return std::abs(value - test_value) < EPSILON; };
|
||||
|
||||
double z;
|
||||
if (including_z)
|
||||
assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()));
|
||||
switch (sync_rotation_type) {
|
||||
case SYNC_ROTATION_NONE:
|
||||
// z only rotation -> keep instance z
|
||||
// The X,Y rotations should be synchronized from start to end of the rotation.
|
||||
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
|
||||
break;
|
||||
case SYNC_ROTATION_FULL:
|
||||
// rotation comes from place on face -> force given z
|
||||
z = rotation(2);
|
||||
else if (is_approx(rotation(0), m_cache.volumes_data[j].get_instance_rotation()(0)) && is_approx(rotation(1), m_cache.volumes_data[j].get_instance_rotation()(1)))
|
||||
// z only rotation -> keep instance z
|
||||
z = v->get_instance_rotation()(2);
|
||||
else
|
||||
// generic rotation -> update instance z
|
||||
z = m_cache.volumes_data[j].get_instance_rotation()(2) + rotation(2);
|
||||
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2)));
|
||||
break;
|
||||
case SYNC_ROTATION_GENERAL:
|
||||
// generic rotation -> update instance z with the delta of the rotation.
|
||||
double z_diff = rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
|
||||
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
|
||||
break;
|
||||
}
|
||||
|
||||
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), z));
|
||||
v->set_instance_scaling_factor(scaling_factor);
|
||||
v->set_instance_mirror(mirror);
|
||||
|
||||
done.insert(j);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
verify_instances_rotation_synchronized(*m_model, *m_volumes);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::_synchronize_unselected_volumes()
|
||||
|
@ -2815,14 +2946,11 @@ void GLCanvas3D::Selection::_ensure_on_bed()
|
|||
}
|
||||
}
|
||||
|
||||
const float GLCanvas3D::Gizmos::OverlayIconsScale = 1.0f;
|
||||
const float GLCanvas3D::Gizmos::OverlayBorder = 5.0f;
|
||||
const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayIconsScale;
|
||||
|
||||
GLCanvas3D::Gizmos::Gizmos()
|
||||
: m_enabled(false)
|
||||
, m_current(Undefined)
|
||||
{
|
||||
set_overlay_scale(1.0);
|
||||
}
|
||||
|
||||
GLCanvas3D::Gizmos::~Gizmos()
|
||||
|
@ -2926,6 +3054,13 @@ void GLCanvas3D::Gizmos::set_enabled(bool enable)
|
|||
m_enabled = enable;
|
||||
}
|
||||
|
||||
void GLCanvas3D::Gizmos::set_overlay_scale(float scale)
|
||||
{
|
||||
m_overlay_icons_scale = scale;
|
||||
m_overlay_border = 5.0f * scale;
|
||||
m_overlay_gap_y = 5.0f * scale;
|
||||
}
|
||||
|
||||
std::string GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const GLCanvas3D::Selection& selection)
|
||||
{
|
||||
std::string name = "";
|
||||
|
@ -2935,22 +3070,22 @@ std::string GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, con
|
|||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float height = _get_total_overlay_height();
|
||||
float top_y = 0.5f * (cnv_h - height) + OverlayBorder;
|
||||
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
|
||||
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
float icon_size = (float)it->second->get_textures_size() * OverlayIconsScale;
|
||||
float icon_size = (float)it->second->get_textures_size() * m_overlay_icons_scale;
|
||||
|
||||
bool inside = (OverlayBorder <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= OverlayBorder + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size);
|
||||
bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size);
|
||||
if (inside)
|
||||
name = it->second->get_name();
|
||||
|
||||
if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
|
||||
it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
|
||||
|
||||
top_y += (icon_size + OverlayGapY);
|
||||
top_y += (icon_size + m_overlay_gap_y);
|
||||
}
|
||||
|
||||
return name;
|
||||
|
@ -2963,15 +3098,15 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec
|
|||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float height = _get_total_overlay_height();
|
||||
float top_y = 0.5f * (cnv_h - height) + OverlayBorder;
|
||||
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
|
||||
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
float icon_size = (float)it->second->get_textures_size() * OverlayIconsScale;
|
||||
float icon_size = (float)it->second->get_textures_size() * m_overlay_icons_scale;
|
||||
|
||||
bool inside = (OverlayBorder <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= OverlayBorder + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size);
|
||||
bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size);
|
||||
if (it->second->is_activable(selection) && inside)
|
||||
{
|
||||
if ((it->second->get_state() == GLGizmoBase::On))
|
||||
|
@ -2988,7 +3123,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec
|
|||
else
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
|
||||
top_y += (icon_size + OverlayGapY);
|
||||
top_y += (icon_size + m_overlay_gap_y);
|
||||
}
|
||||
|
||||
GizmosMap::iterator it = m_gizmos.find(m_current);
|
||||
|
@ -3060,18 +3195,18 @@ bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const
|
|||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float height = _get_total_overlay_height();
|
||||
float top_y = 0.5f * (cnv_h - height) + OverlayBorder;
|
||||
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
float icon_size = (float)it->second->get_textures_size() * OverlayIconsScale;
|
||||
float icon_size = (float)it->second->get_textures_size() * m_overlay_icons_scale;
|
||||
|
||||
if ((OverlayBorder <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= OverlayBorder + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size))
|
||||
if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size))
|
||||
return true;
|
||||
|
||||
top_y += (icon_size + OverlayGapY);
|
||||
top_y += (icon_size + m_overlay_gap_y);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -3344,7 +3479,7 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
|
|||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
float height = _get_total_overlay_height();
|
||||
float scaled_border = OverlayBorder * inv_zoom;
|
||||
float scaled_border = m_overlay_border * inv_zoom;
|
||||
|
||||
float top_x = (-0.5f * cnv_w) * inv_zoom;
|
||||
float top_y = (0.5f * height) * inv_zoom;
|
||||
|
@ -3389,7 +3524,7 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
|
|||
bg_uv_left = bg_uv_i_left;
|
||||
bg_i_left = bg_left;
|
||||
|
||||
if ((OverlayBorder > 0) && (bg_uv_top != bg_uv_i_top))
|
||||
if ((m_overlay_border > 0) && (bg_uv_top != bg_uv_i_top))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_top, bg_top, { { bg_uv_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_top }, { bg_uv_left, bg_uv_top } });
|
||||
|
@ -3400,15 +3535,15 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
|
|||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_top, bg_top, { { bg_uv_i_right, bg_uv_i_top }, { bg_uv_right, bg_uv_i_top }, { bg_uv_right, bg_uv_top }, { bg_uv_i_right, bg_uv_top } });
|
||||
}
|
||||
|
||||
if ((OverlayBorder > 0) && (bg_uv_left != bg_uv_i_left))
|
||||
if ((m_overlay_border > 0) && (bg_uv_left != bg_uv_i_left))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_bottom, bg_i_top, { { bg_uv_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_left, bg_uv_i_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_bottom, bg_i_top, { { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top } });
|
||||
|
||||
if ((OverlayBorder > 0) && (bg_uv_right != bg_uv_i_right))
|
||||
if ((m_overlay_border > 0) && (bg_uv_right != bg_uv_i_right))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_bottom, bg_i_top, { { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top } });
|
||||
|
||||
if ((OverlayBorder > 0) && (bg_uv_bottom != bg_uv_i_bottom))
|
||||
if ((m_overlay_border > 0) && (bg_uv_bottom != bg_uv_i_bottom))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_bottom, bg_i_bottom, { { bg_uv_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_left, bg_uv_i_bottom } });
|
||||
|
@ -3420,19 +3555,19 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
|
|||
}
|
||||
}
|
||||
|
||||
top_x += OverlayBorder * inv_zoom;
|
||||
top_y -= OverlayBorder * inv_zoom;
|
||||
float scaled_gap_y = OverlayGapY * inv_zoom;
|
||||
top_x += m_overlay_border * inv_zoom;
|
||||
top_y -= m_overlay_border * inv_zoom;
|
||||
float scaled_gap_y = m_overlay_gap_y * inv_zoom;
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
float icon_size = (float)it->second->get_textures_size() * OverlayIconsScale * inv_zoom;
|
||||
float icon_size = (float)it->second->get_textures_size() * m_overlay_icons_scale * inv_zoom;
|
||||
GLTexture::render_texture(it->second->get_texture_id(), top_x, top_x + icon_size, top_y - icon_size, top_y);
|
||||
#if ENABLE_IMGUI
|
||||
if (it->second->get_state() == GLGizmoBase::On)
|
||||
it->second->render_input_window(2.0f * OverlayBorder + icon_size * zoom, 0.5f * cnv_h - top_y * zoom, selection);
|
||||
it->second->render_input_window(2.0f * m_overlay_border + icon_size * zoom, 0.5f * cnv_h - top_y * zoom, selection);
|
||||
#endif // ENABLE_IMGUI
|
||||
top_y -= (icon_size + scaled_gap_y);
|
||||
}
|
||||
|
@ -3447,17 +3582,17 @@ void GLCanvas3D::Gizmos::_render_current_gizmo(const GLCanvas3D::Selection& sele
|
|||
|
||||
float GLCanvas3D::Gizmos::_get_total_overlay_height() const
|
||||
{
|
||||
float height = 2.0f * OverlayBorder;
|
||||
float height = 2.0f * m_overlay_border;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
height += (float)it->second->get_textures_size() * OverlayIconsScale + OverlayGapY;
|
||||
height += (float)it->second->get_textures_size() * m_overlay_icons_scale + m_overlay_gap_y;
|
||||
}
|
||||
|
||||
return height - OverlayGapY;
|
||||
return height - m_overlay_gap_y;
|
||||
}
|
||||
|
||||
float GLCanvas3D::Gizmos::_get_total_overlay_width() const
|
||||
|
@ -3468,10 +3603,10 @@ float GLCanvas3D::Gizmos::_get_total_overlay_width() const
|
|||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
max_icon_width = std::max(max_icon_width, (float)it->second->get_textures_size() * OverlayIconsScale);
|
||||
max_icon_width = std::max(max_icon_width, (float)it->second->get_textures_size() * m_overlay_icons_scale);
|
||||
}
|
||||
|
||||
return max_icon_width + 2.0f * OverlayBorder;
|
||||
return max_icon_width + 2.0f * m_overlay_border;
|
||||
}
|
||||
|
||||
GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const
|
||||
|
@ -3490,7 +3625,7 @@ GLCanvas3D::WarningTexture::WarningTexture()
|
|||
{
|
||||
}
|
||||
|
||||
bool GLCanvas3D::WarningTexture::generate(const std::string& msg)
|
||||
bool GLCanvas3D::WarningTexture::generate(const std::string& msg, const GLCanvas3D& canvas)
|
||||
{
|
||||
reset();
|
||||
|
||||
|
@ -3499,7 +3634,8 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg)
|
|||
|
||||
wxMemoryDC memDC;
|
||||
// select default font
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
const float scale = canvas.get_canvas_size().get_scale_factor();
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale);
|
||||
font.MakeLarger();
|
||||
font.MakeBold();
|
||||
memDC.SetFont(font);
|
||||
|
@ -3647,9 +3783,18 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
|||
wxMemoryDC memDC;
|
||||
wxMemoryDC mask_memDC;
|
||||
|
||||
// calculate scaling
|
||||
const float scale = canvas.get_canvas_size().get_scale_factor();
|
||||
const int scaled_square = std::floor((float)Px_Square * scale);
|
||||
const int scaled_title_offset = Px_Title_Offset * scale;
|
||||
const int scaled_text_offset = Px_Text_Offset * scale;
|
||||
const int scaled_square_contour = Px_Square_Contour * scale;
|
||||
const int scaled_border = Px_Border * scale;
|
||||
|
||||
// select default font
|
||||
memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
mask_memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale);
|
||||
memDC.SetFont(font);
|
||||
mask_memDC.SetFont(font);
|
||||
|
||||
// calculates texture size
|
||||
wxCoord w, h;
|
||||
|
@ -3666,10 +3811,10 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
|||
max_text_height = std::max(max_text_height, (int)h);
|
||||
}
|
||||
|
||||
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;
|
||||
m_original_width = std::max(2 * scaled_border + title_width, 2 * (scaled_border + scaled_square_contour) + scaled_square + scaled_text_offset + max_text_width);
|
||||
m_original_height = 2 * (scaled_border + scaled_square_contour) + title_height + scaled_title_offset + items_count * scaled_square;
|
||||
if (items_count > 1)
|
||||
m_original_height += (items_count - 1) * Px_Square_Contour;
|
||||
m_original_height += (items_count - 1) * scaled_square_contour;
|
||||
|
||||
int pow_of_two_size = (int)next_highest_power_of_2(std::max<uint32_t>(m_original_width, m_original_height));
|
||||
|
||||
|
@ -3693,8 +3838,8 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
|||
memDC.SetTextForeground(use_error_colors ? *wxWHITE : *wxBLACK);
|
||||
mask_memDC.SetTextForeground(*wxWHITE);
|
||||
|
||||
int title_x = Px_Border;
|
||||
int title_y = Px_Border;
|
||||
int title_x = scaled_border;
|
||||
int title_y = scaled_border;
|
||||
memDC.DrawText(title, title_x, title_y);
|
||||
mask_memDC.DrawText(title, title_x, title_y);
|
||||
|
||||
|
@ -3702,12 +3847,12 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
|||
mask_memDC.SetBrush(wxBrush(*wxWHITE));
|
||||
|
||||
// draw icons contours as background
|
||||
int squares_contour_x = Px_Border;
|
||||
int squares_contour_y = Px_Border + title_height + Px_Title_Offset;
|
||||
int squares_contour_width = Px_Square + 2 * Px_Square_Contour;
|
||||
int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour;
|
||||
int squares_contour_x = scaled_border;
|
||||
int squares_contour_y = scaled_border + title_height + scaled_title_offset;
|
||||
int squares_contour_width = scaled_square + 2 * scaled_square_contour;
|
||||
int squares_contour_height = items_count * scaled_square + 2 * scaled_square_contour;
|
||||
if (items_count > 1)
|
||||
squares_contour_height += (items_count - 1) * Px_Square_Contour;
|
||||
squares_contour_height += (items_count - 1) * scaled_square_contour;
|
||||
|
||||
wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]);
|
||||
wxPen pen(color);
|
||||
|
@ -3718,15 +3863,15 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
|||
mask_memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
|
||||
|
||||
// draw items (colored icon + text)
|
||||
int icon_x = squares_contour_x + Px_Square_Contour;
|
||||
int icon_x = squares_contour_x + scaled_square_contour;
|
||||
int icon_x_inner = icon_x + 1;
|
||||
int icon_y = squares_contour_y + Px_Square_Contour;
|
||||
int icon_y_step = Px_Square + Px_Square_Contour;
|
||||
int icon_y = squares_contour_y + scaled_square_contour;
|
||||
int icon_y_step = scaled_square + scaled_square_contour;
|
||||
|
||||
int text_x = icon_x + Px_Square + Px_Text_Offset;
|
||||
int text_y_offset = (Px_Square - max_text_height) / 2;
|
||||
int text_x = icon_x + scaled_square + scaled_text_offset;
|
||||
int text_y_offset = (scaled_square - max_text_height) / 2;
|
||||
|
||||
int px_inner_square = Px_Square - 2;
|
||||
int px_inner_square = scaled_square - 2;
|
||||
|
||||
for (const GCodePreviewData::LegendItem& item : items)
|
||||
{
|
||||
|
@ -3740,7 +3885,7 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
|||
brush.SetColour(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square));
|
||||
memDC.DrawRectangle(wxRect(icon_x, icon_y, scaled_square, scaled_square));
|
||||
|
||||
// draw icon interior
|
||||
color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]);
|
||||
|
@ -3849,6 +3994,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
|
|||
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
||||
: m_canvas(canvas)
|
||||
, m_context(nullptr)
|
||||
#if ENABLE_RETINA_GL
|
||||
, m_retina_helper(nullptr)
|
||||
#endif
|
||||
, m_in_render(false)
|
||||
, m_toolbar(GLToolbar::Normal)
|
||||
, m_view_toolbar(nullptr)
|
||||
|
@ -3882,8 +4030,12 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
|||
, m_external_gizmo_widgets_parent(nullptr)
|
||||
#endif // not ENABLE_IMGUI
|
||||
{
|
||||
if (m_canvas != nullptr)
|
||||
if (m_canvas != nullptr) {
|
||||
m_timer.SetOwner(m_canvas);
|
||||
#if ENABLE_RETINA_GL
|
||||
m_retina_helper.reset(new RetinaHelper(canvas));
|
||||
#endif
|
||||
}
|
||||
|
||||
m_selection.set_volumes(&m_volumes.volumes);
|
||||
}
|
||||
|
@ -4238,9 +4390,6 @@ void GLCanvas3D::set_viewport_from_scene(const GLCanvas3D& other)
|
|||
m_camera.set_scene_box(other.m_camera.get_scene_box(), *this);
|
||||
m_camera.set_target(other.m_camera.get_target(), *this);
|
||||
m_camera.zoom = other.m_camera.zoom;
|
||||
#if ENABLE_REWORKED_BED_SHAPE_CHANGE
|
||||
m_requires_zoom_to_bed = false;
|
||||
#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
|
@ -4519,7 +4668,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
}
|
||||
if (printer_technology == ptSLA) {
|
||||
const SLAPrint *sla_print = this->sla_print();
|
||||
#ifdef _DEBUG
|
||||
#ifdef _DEBUG
|
||||
// Verify that the SLAPrint object is synchronized with m_model.
|
||||
check_model_ids_equal(*m_model, sla_print->model());
|
||||
#endif /* _DEBUG */
|
||||
|
@ -5010,6 +5159,12 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt)
|
|||
|
||||
void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
const float scale = m_retina_helper->get_scale_factor();
|
||||
evt.SetX(evt.GetX() * scale);
|
||||
evt.SetY(evt.GetY() * scale);
|
||||
#endif
|
||||
|
||||
#if ENABLE_IMGUI
|
||||
auto imgui = wxGetApp().imgui();
|
||||
if (imgui->update_mouse_data(evt)) {
|
||||
|
@ -5232,7 +5387,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
wxGetApp().obj_manipul()->update_settings_value(m_selection);
|
||||
// forces a frame render to update the view before the context menu is shown
|
||||
render();
|
||||
post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, pos.cast<double>()));
|
||||
|
||||
Vec2d logical_pos = pos.cast<double>();
|
||||
#if ENABLE_RETINA_GL
|
||||
const float factor = m_retina_helper->get_scale_factor();
|
||||
logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
|
||||
#endif
|
||||
post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5498,7 +5659,15 @@ Size GLCanvas3D::get_canvas_size() const
|
|||
if (m_canvas != nullptr)
|
||||
m_canvas->GetSize(&w, &h);
|
||||
|
||||
return Size(w, h);
|
||||
#if ENABLE_RETINA_GL
|
||||
const float factor = m_retina_helper->get_scale_factor();
|
||||
w *= factor;
|
||||
h *= factor;
|
||||
#else
|
||||
const float factor = 1.0;
|
||||
#endif
|
||||
|
||||
return Size(w, h, factor);
|
||||
}
|
||||
|
||||
Point GLCanvas3D::get_local_mouse_position() const
|
||||
|
@ -5805,6 +5974,26 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc
|
|||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::update_ui_from_settings()
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
const float orig_scaling = m_retina_helper->get_scale_factor();
|
||||
|
||||
const bool use_retina = wxGetApp().app_config->get("use_retina_opengl") == "1";
|
||||
BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Use Retina OpenGL: " << use_retina;
|
||||
m_retina_helper->set_use_retina(use_retina);
|
||||
const float new_scaling = m_retina_helper->get_scale_factor();
|
||||
|
||||
if (new_scaling != orig_scaling) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling;
|
||||
|
||||
m_camera.zoom /= orig_scaling;
|
||||
m_camera.zoom *= new_scaling;
|
||||
_refresh_if_shown_on_screen();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_shown_on_screen() const
|
||||
{
|
||||
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
|
||||
|
@ -5958,6 +6147,9 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
|
|||
|
||||
#if ENABLE_IMGUI
|
||||
wxGetApp().imgui()->set_display_size((float)w, (float)h);
|
||||
#if ENABLE_RETINA_GL
|
||||
wxGetApp().imgui()->set_style_scaling(m_retina_helper->get_scale_factor());
|
||||
#endif // ENABLE_RETINA_GL
|
||||
#endif // ENABLE_IMGUI
|
||||
|
||||
// ensures that this canvas is current
|
||||
|
@ -6238,10 +6430,15 @@ void GLCanvas3D::_render_background() const
|
|||
|
||||
void GLCanvas3D::_render_bed(float theta) const
|
||||
{
|
||||
float scale_factor = 1.0;
|
||||
#if ENABLE_RETINA_GL
|
||||
scale_factor = m_retina_helper->get_scale_factor();
|
||||
#endif
|
||||
|
||||
#if ENABLE_PRINT_BED_MODELS
|
||||
m_bed.render(theta, m_use_VBOs);
|
||||
m_bed.render(theta, m_use_VBOs, scale_factor);
|
||||
#else
|
||||
m_bed.render(theta);
|
||||
m_bed.render(theta, scale_factor);
|
||||
#endif // ENABLE_PRINT_BED_MODELS
|
||||
}
|
||||
|
||||
|
@ -6320,8 +6517,13 @@ void GLCanvas3D::_render_objects() const
|
|||
|
||||
void GLCanvas3D::_render_selection() const
|
||||
{
|
||||
float scale_factor = 1.0;
|
||||
#if ENABLE_RETINA_GL
|
||||
scale_factor = m_retina_helper->get_scale_factor();
|
||||
#endif
|
||||
|
||||
if (!m_gizmos.is_running())
|
||||
m_selection.render();
|
||||
m_selection.render(scale_factor);
|
||||
}
|
||||
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
|
@ -6404,18 +6606,28 @@ void GLCanvas3D::_render_current_gizmo() const
|
|||
|
||||
void GLCanvas3D::_render_gizmos_overlay() const
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
m_gizmos.set_overlay_scale(m_retina_helper->get_scale_factor());
|
||||
#endif
|
||||
m_gizmos.render_overlay(*this, m_selection);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_toolbar() const
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
m_toolbar.set_icons_scale(m_retina_helper->get_scale_factor());
|
||||
#endif
|
||||
m_toolbar.render(*this);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_view_toolbar() const
|
||||
{
|
||||
if (m_view_toolbar != nullptr)
|
||||
if (m_view_toolbar != nullptr) {
|
||||
#if ENABLE_RETINA_GL
|
||||
m_view_toolbar->set_icons_scale(m_retina_helper->get_scale_factor());
|
||||
#endif
|
||||
m_view_toolbar->render(*this);
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SHOW_CAMERA_TARGET
|
||||
|
@ -8116,7 +8328,7 @@ void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data,
|
|||
|
||||
void GLCanvas3D::_generate_warning_texture(const std::string& msg)
|
||||
{
|
||||
m_warning_texture.generate(msg);
|
||||
m_warning_texture.generate(msg, *this);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_reset_warning_texture()
|
||||
|
@ -8141,6 +8353,10 @@ void GLCanvas3D::_resize_toolbars() const
|
|||
float zoom = get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
m_toolbar.set_icons_scale(m_retina_helper->get_scale_factor());
|
||||
#endif
|
||||
|
||||
GLToolbar::Layout::EOrientation orientation = m_toolbar.get_layout_orientation();
|
||||
|
||||
switch (m_toolbar.get_layout_type())
|
||||
|
@ -8184,6 +8400,10 @@ void GLCanvas3D::_resize_toolbars() const
|
|||
|
||||
if (m_view_toolbar != nullptr)
|
||||
{
|
||||
#if ENABLE_RETINA_GL
|
||||
m_view_toolbar->set_icons_scale(m_retina_helper->get_scale_factor());
|
||||
#endif
|
||||
|
||||
// places the toolbar on the bottom-left corner of the 3d scene
|
||||
float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar->get_height()) * inv_zoom;
|
||||
float left = -0.5f * (float)cnv_size.get_width() * inv_zoom;
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
#define slic3r_GLCanvas3D_hpp_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <memory>
|
||||
|
||||
#include "libslic3r/Technologies.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "GLToolbar.hpp"
|
||||
#include "Event.hpp"
|
||||
|
@ -20,6 +22,9 @@ class wxTimerEvent;
|
|||
class wxPaintEvent;
|
||||
class wxGLCanvas;
|
||||
|
||||
// Support for Retina OpenGL on Mac OS
|
||||
#define ENABLE_RETINA_GL __APPLE__
|
||||
|
||||
class GLUquadric;
|
||||
typedef class GLUquadric GLUquadricObj;
|
||||
|
||||
|
@ -36,6 +41,10 @@ namespace GUI {
|
|||
|
||||
class GLGizmoBase;
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
class RetinaHelper;
|
||||
#endif
|
||||
|
||||
class GeometryBuffer
|
||||
{
|
||||
std::vector<float> m_vertices;
|
||||
|
@ -55,16 +64,20 @@ class Size
|
|||
{
|
||||
int m_width;
|
||||
int m_height;
|
||||
float m_scale_factor;
|
||||
|
||||
public:
|
||||
Size();
|
||||
Size(int width, int height);
|
||||
Size(int width, int height, float scale_factor = 1.0);
|
||||
|
||||
int get_width() const;
|
||||
void set_width(int width);
|
||||
|
||||
int get_height() const;
|
||||
void set_height(int height);
|
||||
|
||||
int get_scale_factor() const;
|
||||
void set_scale_factor(int height);
|
||||
};
|
||||
|
||||
class Rect
|
||||
|
@ -209,6 +222,8 @@ class GLCanvas3D
|
|||
mutable GLBed m_model;
|
||||
#endif // ENABLE_PRINT_BED_MODELS
|
||||
|
||||
mutable float m_scale_factor;
|
||||
|
||||
public:
|
||||
Bed();
|
||||
|
||||
|
@ -224,9 +239,9 @@ class GLCanvas3D
|
|||
Point point_projection(const Point& point) const;
|
||||
|
||||
#if ENABLE_PRINT_BED_MODELS
|
||||
void render(float theta, bool useVBOs) const;
|
||||
void render(float theta, bool useVBOs, float scale_factor) const;
|
||||
#else
|
||||
void render(float theta) const;
|
||||
void render(float theta, float scale_factor) const;
|
||||
#endif // ENABLE_PRINT_BED_MODELS
|
||||
|
||||
private:
|
||||
|
@ -297,6 +312,9 @@ class GLCanvas3D
|
|||
};
|
||||
|
||||
private:
|
||||
static const float THICKNESS_BAR_WIDTH;
|
||||
static const float THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
|
||||
bool m_use_legacy_opengl;
|
||||
bool m_enabled;
|
||||
Shader m_shader;
|
||||
|
@ -380,6 +398,9 @@ class GLCanvas3D
|
|||
void _render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const;
|
||||
void _render_profile(const Rect& bar_rect) const;
|
||||
void update_slicing_parameters();
|
||||
|
||||
static float thickness_bar_width(const GLCanvas3D &canvas);
|
||||
static float reset_button_height(const GLCanvas3D &canvas);
|
||||
};
|
||||
|
||||
struct Mouse
|
||||
|
@ -536,6 +557,8 @@ public:
|
|||
mutable GLArrow m_arrow;
|
||||
mutable GLCurvedArrow m_curved_arrow;
|
||||
|
||||
mutable float m_scale_factor;
|
||||
|
||||
public:
|
||||
Selection();
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
|
@ -617,7 +640,7 @@ public:
|
|||
|
||||
void erase();
|
||||
|
||||
void render() const;
|
||||
void render(float scale_factor = 1.0) const;
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
void render_center() const;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
@ -647,7 +670,15 @@ public:
|
|||
void _render_sidebar_rotation_hint(Axis axis) const;
|
||||
void _render_sidebar_scale_hint(Axis axis) const;
|
||||
void _render_sidebar_size_hint(Axis axis, double length) const;
|
||||
void _synchronize_unselected_instances(bool including_z = false);
|
||||
enum SyncRotationType {
|
||||
// Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
|
||||
SYNC_ROTATION_NONE = 0,
|
||||
// Synchronize fully. Used from "place on bed" feature.
|
||||
SYNC_ROTATION_FULL = 1,
|
||||
// Synchronize after rotation by an axis not parallel with Z.
|
||||
SYNC_ROTATION_GENERAL = 2,
|
||||
};
|
||||
void _synchronize_unselected_instances(SyncRotationType sync_rotation_type);
|
||||
void _synchronize_unselected_volumes();
|
||||
void _ensure_on_bed();
|
||||
};
|
||||
|
@ -680,10 +711,6 @@ public:
|
|||
private:
|
||||
class Gizmos
|
||||
{
|
||||
static const float OverlayIconsScale;
|
||||
static const float OverlayBorder;
|
||||
static const float OverlayGapY;
|
||||
|
||||
public:
|
||||
enum EType : unsigned char
|
||||
{
|
||||
|
@ -704,6 +731,10 @@ private:
|
|||
BackgroundTexture m_background_texture;
|
||||
EType m_current;
|
||||
|
||||
float m_overlay_icons_scale;
|
||||
float m_overlay_border;
|
||||
float m_overlay_gap_y;
|
||||
|
||||
public:
|
||||
Gizmos();
|
||||
~Gizmos();
|
||||
|
@ -713,6 +744,8 @@ private:
|
|||
bool is_enabled() const;
|
||||
void set_enabled(bool enable);
|
||||
|
||||
void set_overlay_scale(float scale);
|
||||
|
||||
std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
|
||||
void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
|
||||
void update_on_off_state(const Selection& selection);
|
||||
|
@ -802,7 +835,7 @@ private:
|
|||
public:
|
||||
WarningTexture();
|
||||
|
||||
bool generate(const std::string& msg);
|
||||
bool generate(const std::string& msg, const GLCanvas3D& canvas);
|
||||
|
||||
void render(const GLCanvas3D& canvas) const;
|
||||
};
|
||||
|
@ -832,6 +865,9 @@ private:
|
|||
|
||||
wxGLCanvas* m_canvas;
|
||||
wxGLContext* m_context;
|
||||
#if ENABLE_RETINA_GL
|
||||
std::unique_ptr<RetinaHelper> m_retina_helper;
|
||||
#endif
|
||||
bool m_in_render;
|
||||
LegendTexture m_legend_texture;
|
||||
WarningTexture m_warning_texture;
|
||||
|
@ -1030,6 +1066,8 @@ public:
|
|||
|
||||
void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on);
|
||||
|
||||
void update_ui_from_settings();
|
||||
|
||||
private:
|
||||
bool _is_shown_on_screen() const;
|
||||
#if !ENABLE_REWORKED_BED_SHAPE_CHANGE
|
||||
|
|
|
@ -1428,6 +1428,7 @@ void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection)
|
|||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
assert(m_planes_valid);
|
||||
m_normal = m_planes[m_hover_id].normal;
|
||||
m_starting_center = selection.get_bounding_box().center();
|
||||
}
|
||||
|
@ -1446,6 +1447,8 @@ void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const
|
|||
::glPushMatrix();
|
||||
::glMultMatrixd(m.data());
|
||||
::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z());
|
||||
if (this->is_plane_update_necessary())
|
||||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
||||
for (int i = 0; i < (int)m_planes.size(); ++i)
|
||||
{
|
||||
if (i == m_hover_id)
|
||||
|
@ -1478,6 +1481,8 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
|
|||
::glPushMatrix();
|
||||
::glMultMatrixd(m.data());
|
||||
::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z());
|
||||
if (this->is_plane_update_necessary())
|
||||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
||||
for (int i = 0; i < (int)m_planes.size(); ++i)
|
||||
{
|
||||
::glColor3f(1.0f, 1.0f, picking_color_component(i));
|
||||
|
@ -1497,11 +1502,11 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
|
|||
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
|
||||
{
|
||||
m_starting_center = Vec3d::Zero();
|
||||
bool object_changed = m_model_object != model_object;
|
||||
if (m_model_object != model_object) {
|
||||
m_planes.clear();
|
||||
m_planes_valid = false;
|
||||
}
|
||||
m_model_object = model_object;
|
||||
|
||||
if (model_object && (object_changed || is_plane_update_necessary()))
|
||||
update_planes();
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::update_planes()
|
||||
|
@ -1701,6 +1706,8 @@ void GLGizmoFlatten::update_planes()
|
|||
}
|
||||
m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor();
|
||||
m_first_instance_mirror = m_model_object->instances.front()->get_mirror();
|
||||
|
||||
m_planes_valid = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1709,7 +1716,7 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
|
|||
if (m_state != On || !m_model_object || m_model_object->instances.empty())
|
||||
return false;
|
||||
|
||||
if (m_model_object->volumes.size() != m_volumes_matrices.size())
|
||||
if (! m_planes_valid || m_model_object->volumes.size() != m_volumes_matrices.size())
|
||||
return true;
|
||||
|
||||
// We want to recalculate when the scale changes - some planes could (dis)appear.
|
||||
|
|
|
@ -408,6 +408,7 @@ private:
|
|||
Vec3d m_first_instance_mirror;
|
||||
|
||||
std::vector<PlaneData> m_planes;
|
||||
bool m_planes_valid = false;
|
||||
mutable Vec3d m_starting_center;
|
||||
const ModelObject* m_model_object = nullptr;
|
||||
std::vector<const Transform3d*> instances_matrices;
|
||||
|
|
|
@ -468,12 +468,12 @@ float GLToolbar::get_width_horizontal() const
|
|||
|
||||
float GLToolbar::get_width_vertical() const
|
||||
{
|
||||
return 2.0f * m_layout.border + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
}
|
||||
|
||||
float GLToolbar::get_height_horizontal() const
|
||||
{
|
||||
return 2.0f * m_layout.border + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
}
|
||||
|
||||
float GLToolbar::get_height_vertical() const
|
||||
|
@ -483,33 +483,36 @@ float GLToolbar::get_height_vertical() const
|
|||
|
||||
float GLToolbar::get_main_size() const
|
||||
{
|
||||
float size = 2.0f * m_layout.border;
|
||||
float size = 2.0f * m_layout.border * m_layout.icons_scale;
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
if (m_items[i]->is_separator())
|
||||
size += m_layout.separator_size;
|
||||
size += m_layout.separator_size * m_layout.icons_scale;
|
||||
else
|
||||
size += (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
}
|
||||
|
||||
if (m_items.size() > 1)
|
||||
size += ((float)m_items.size() - 1.0f) * m_layout.gap_size;
|
||||
size += ((float)m_items.size() - 1.0f) * m_layout.gap_size * m_layout.icons_scale;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent)
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = parent.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * inv_zoom;
|
||||
float scaled_separator_size = m_layout.separator_size * inv_zoom;
|
||||
float scaled_gap_size = m_layout.gap_size * inv_zoom;
|
||||
float scaled_border = m_layout.border * inv_zoom;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
||||
float separator_stride = scaled_separator_size + scaled_gap_size;
|
||||
float icon_stride = scaled_icons_size + scaled_gap_size;
|
||||
|
@ -591,16 +594,19 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
|
|||
|
||||
std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent)
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = parent.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * inv_zoom;
|
||||
float scaled_separator_size = m_layout.separator_size * inv_zoom;
|
||||
float scaled_gap_size = m_layout.gap_size * inv_zoom;
|
||||
float scaled_border = m_layout.border * inv_zoom;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
||||
float separator_stride = scaled_separator_size + scaled_gap_size;
|
||||
float icon_stride = scaled_icons_size + scaled_gap_size;
|
||||
|
@ -682,16 +688,19 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
|
|||
|
||||
int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = parent.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * inv_zoom;
|
||||
float scaled_separator_size = m_layout.separator_size * inv_zoom;
|
||||
float scaled_gap_size = m_layout.gap_size * inv_zoom;
|
||||
float scaled_border = m_layout.border * inv_zoom;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
||||
float separator_stride = scaled_separator_size + scaled_gap_size;
|
||||
float icon_stride = scaled_icons_size + scaled_gap_size;
|
||||
|
@ -724,16 +733,19 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3
|
|||
|
||||
int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& parent) const
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = parent.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * inv_zoom;
|
||||
float scaled_separator_size = m_layout.separator_size * inv_zoom;
|
||||
float scaled_gap_size = m_layout.gap_size * inv_zoom;
|
||||
float scaled_border = m_layout.border * inv_zoom;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
||||
float separator_stride = scaled_separator_size + scaled_gap_size;
|
||||
float icon_stride = scaled_icons_size + scaled_gap_size;
|
||||
|
@ -774,11 +786,12 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
|
|||
|
||||
float zoom = parent.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float factor = inv_zoom * m_layout.icons_scale;
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * inv_zoom;
|
||||
float scaled_separator_size = m_layout.separator_size * inv_zoom;
|
||||
float scaled_gap_size = m_layout.gap_size * inv_zoom;
|
||||
float scaled_border = m_layout.border * inv_zoom;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
float scaled_width = get_width() * inv_zoom;
|
||||
float scaled_height = get_height() * inv_zoom;
|
||||
|
||||
|
@ -899,11 +912,12 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
|
|||
|
||||
float zoom = parent.get_camera_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float factor = inv_zoom * m_layout.icons_scale;
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * inv_zoom;
|
||||
float scaled_separator_size = m_layout.separator_size * inv_zoom;
|
||||
float scaled_gap_size = m_layout.gap_size * inv_zoom;
|
||||
float scaled_border = m_layout.border * inv_zoom;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * factor;
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
float scaled_width = get_width() * inv_zoom;
|
||||
float scaled_height = get_height() * inv_zoom;
|
||||
|
||||
|
|
|
@ -270,16 +270,11 @@ void GUI_App::set_label_clr_sys(const wxColour& clr) {
|
|||
|
||||
void GUI_App::recreate_GUI()
|
||||
{
|
||||
std::cerr << "recreate_GUI" << std::endl;
|
||||
// to make sure nobody accesses data from the soon-to-be-destroyed widgets:
|
||||
tabs_list.clear();
|
||||
plater_ = nullptr;
|
||||
|
||||
clear_tabs_list();
|
||||
if (plater_) {
|
||||
// before creating a new plater let's delete old one
|
||||
plater_->Destroy();
|
||||
plater_ = nullptr;
|
||||
}
|
||||
|
||||
MainFrame* topwindow = dynamic_cast<MainFrame*>(GetTopWindow());
|
||||
MainFrame* topwindow = mainframe;
|
||||
mainframe = new MainFrame();
|
||||
sidebar().obj_list()->init_objects(); // propagate model objects to object list
|
||||
|
||||
|
@ -691,15 +686,6 @@ void GUI_App::load_current_presets()
|
|||
}
|
||||
}
|
||||
|
||||
void GUI_App::clear_tabs_list()
|
||||
{
|
||||
for (auto tab : tabs_list) {
|
||||
tab->Destroy();
|
||||
tab = nullptr;
|
||||
}
|
||||
tabs_list.clear();
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// wxWidgets override to get an event on open files.
|
||||
void GUI_App::MacOpenFiles(const wxArrayString &fileNames)
|
||||
|
|
|
@ -134,7 +134,6 @@ public:
|
|||
bool check_unsaved_changes();
|
||||
bool checked_tab(Tab* tab);
|
||||
void load_current_presets();
|
||||
void clear_tabs_list();
|
||||
|
||||
#ifdef __APPLE__
|
||||
// wxWidgets override to get an event on open files.
|
||||
|
|
|
@ -626,7 +626,8 @@ const std::vector<std::string>& ObjectList::get_options_for_bundle(const wxStrin
|
|||
}
|
||||
#endif
|
||||
|
||||
return std::vector<std::string> {};
|
||||
static std::vector<std::string> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const bool is_part)
|
||||
|
@ -1370,15 +1371,12 @@ bool ObjectList::is_splittable()
|
|||
if (!get_volume_by_item(item, volume) || !volume)
|
||||
return false;
|
||||
|
||||
if (volume->is_splittable() != -1) // if is_splittable value is already known
|
||||
return volume->is_splittable() == 0 ? false : true;
|
||||
|
||||
TriangleMeshPtrs meshptrs = volume->mesh.split();
|
||||
bool splittable = meshptrs.size() > 1;
|
||||
for (TriangleMesh* m : meshptrs) { delete m; }
|
||||
|
||||
volume->set_splittable(splittable ? 1 : 0);
|
||||
return splittable;
|
||||
int splittable = volume->is_splittable();
|
||||
if (splittable == -1) {
|
||||
splittable = (int)volume->mesh.has_multiple_patches();
|
||||
volume->set_splittable(splittable);
|
||||
}
|
||||
return splittable != 0;
|
||||
}
|
||||
|
||||
bool ObjectList::selected_instances_of_same_object()
|
||||
|
|
|
@ -267,7 +267,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
bool changed_box = false;
|
||||
if (!m_cache.instance.matches_object(obj_idx))
|
||||
{
|
||||
m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size());
|
||||
m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size());
|
||||
changed_box = true;
|
||||
}
|
||||
if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale))
|
||||
|
@ -278,7 +278,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
m_new_size = Vec3d::Zero();
|
||||
#else
|
||||
if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size()))
|
||||
m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size();
|
||||
m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size();
|
||||
else
|
||||
// this should never happen
|
||||
m_new_size = Vec3d::Zero();
|
||||
|
|
|
@ -109,6 +109,7 @@ public:
|
|||
virtual ~Preview();
|
||||
|
||||
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
|
||||
GLCanvas3D* get_canvas3d() { return m_canvas; }
|
||||
|
||||
void set_view_toolbar(GLToolbar* toolbar);
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
@ -24,6 +26,7 @@ namespace GUI {
|
|||
|
||||
ImGuiWrapper::ImGuiWrapper()
|
||||
: m_font_texture(0)
|
||||
, m_style_scaling(1.0)
|
||||
, m_mouse_buttons(0)
|
||||
, m_disabled(false)
|
||||
{
|
||||
|
@ -39,18 +42,9 @@ bool ImGuiWrapper::init()
|
|||
{
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), 18.0f);
|
||||
if (font == nullptr) {
|
||||
font = io.Fonts->AddFontDefault();
|
||||
if (font == nullptr)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
m_fonts.insert(FontsMap::value_type("Noto Sans Regular 18", font));
|
||||
}
|
||||
init_default_font(m_style_scaling);
|
||||
|
||||
io.IniFilename = nullptr;
|
||||
ImGui::GetIO().IniFilename = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -62,6 +56,15 @@ void ImGuiWrapper::set_display_size(float w, float h)
|
|||
io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ImGuiWrapper::set_style_scaling(float scaling)
|
||||
{
|
||||
if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) {
|
||||
ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling);
|
||||
init_default_font(scaling);
|
||||
m_style_scaling = scaling;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
@ -93,6 +96,7 @@ void ImGuiWrapper::render()
|
|||
void ImGuiWrapper::set_next_window_pos(float x, float y, int flag)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag);
|
||||
ImGui::SetNextWindowSize(ImVec2(0.0, 0.0));
|
||||
}
|
||||
|
||||
void ImGuiWrapper::set_next_window_bg_alpha(float alpha)
|
||||
|
@ -198,6 +202,23 @@ bool ImGuiWrapper::want_any_input() const
|
|||
return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput;
|
||||
}
|
||||
|
||||
void ImGuiWrapper::init_default_font(float scaling)
|
||||
{
|
||||
static const float font_size = 18.0f;
|
||||
|
||||
destroy_fonts_texture();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->Clear();
|
||||
ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size * scaling);
|
||||
if (font == nullptr) {
|
||||
font = io.Fonts->AddFontDefault();
|
||||
if (font == nullptr) {
|
||||
throw std::runtime_error("ImGui: Could not load deafult font");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiWrapper::create_device_objects()
|
||||
{
|
||||
create_fonts_texture();
|
||||
|
|
|
@ -21,6 +21,7 @@ class ImGuiWrapper
|
|||
|
||||
FontsMap m_fonts;
|
||||
unsigned m_font_texture;
|
||||
float m_style_scaling;
|
||||
unsigned m_mouse_buttons;
|
||||
bool m_disabled;
|
||||
|
||||
|
@ -32,6 +33,7 @@ public:
|
|||
void read_glsl_version();
|
||||
|
||||
void set_display_size(float w, float h);
|
||||
void set_style_scaling(float scaling);
|
||||
bool update_mouse_data(wxMouseEvent &evt);
|
||||
|
||||
void new_frame();
|
||||
|
@ -58,6 +60,7 @@ public:
|
|||
bool want_text_input() const;
|
||||
bool want_any_input() const;
|
||||
private:
|
||||
void init_default_font(float scaling);
|
||||
void create_device_objects();
|
||||
void create_fonts_texture();
|
||||
void render_draw_data(ImDrawData *draw_data);
|
||||
|
|
|
@ -95,14 +95,10 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL
|
|||
_3DScene::remove_all_canvases();
|
||||
// Slic3r::GUI::deregister_on_request_update_callback();
|
||||
|
||||
// destroy and set to null tabs and a platter
|
||||
// set to null tabs and a platter
|
||||
// to avoid any manipulations with them from App->wxEVT_IDLE after of the mainframe closing
|
||||
wxGetApp().clear_tabs_list();
|
||||
if (wxGetApp().plater_) {
|
||||
// before creating a new plater let's delete old one
|
||||
wxGetApp().plater_->Destroy();
|
||||
wxGetApp().plater_ = nullptr;
|
||||
}
|
||||
wxGetApp().tabs_list.clear();
|
||||
wxGetApp().plater_ = nullptr;
|
||||
|
||||
// propagate event
|
||||
event.Skip();
|
||||
|
@ -113,6 +109,7 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL
|
|||
update_ui_from_settings(); // FIXME (?)
|
||||
}
|
||||
|
||||
|
||||
void MainFrame::init_tabpanel()
|
||||
{
|
||||
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL);
|
||||
|
|
|
@ -1272,6 +1272,11 @@ void Plater::priv::update_ui_from_settings()
|
|||
// $self->{buttons_sizer}->Show($self->{btn_reslice}, ! wxTheApp->{app_config}->get("background_processing"));
|
||||
// $self->{buttons_sizer}->Layout;
|
||||
// }
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
view3D->get_canvas3d()->update_ui_from_settings();
|
||||
preview->get_canvas3d()->update_ui_from_settings();
|
||||
#endif
|
||||
}
|
||||
|
||||
ProgressStatusBar* Plater::priv::statusbar()
|
||||
|
@ -1463,29 +1468,40 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
return obj_idxs;
|
||||
}
|
||||
|
||||
// #define AUTOPLACEMENT_ON_LOAD
|
||||
|
||||
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &model_objects)
|
||||
{
|
||||
const BoundingBoxf bed_shape = bed_shape_bb();
|
||||
const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast<double>(), 1.0) - 2.0 * Vec3d::Ones();
|
||||
|
||||
#ifndef AUTOPLACEMENT_ON_LOAD
|
||||
bool need_arrange = false;
|
||||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
bool scaled_down = false;
|
||||
std::vector<size_t> obj_idxs;
|
||||
unsigned int obj_count = model.objects.size();
|
||||
|
||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||
ModelInstancePtrs new_instances;
|
||||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
for (ModelObject *model_object : model_objects) {
|
||||
auto *object = model.add_object(*model_object);
|
||||
std::string object_name = object->name.empty() ? fs::path(object->input_file).filename().string() : object->name;
|
||||
obj_idxs.push_back(obj_count++);
|
||||
|
||||
if (model_object->instances.empty()) {
|
||||
// if object has no defined position(s) we need to rearrange everything after loading
|
||||
need_arrange = true;
|
||||
|
||||
// add a default instance and center object around origin
|
||||
object->center_around_origin(); // also aligns object to Z = 0
|
||||
ModelInstance* instance = object->add_instance();
|
||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||
object->center_around_origin();
|
||||
new_instances.emplace_back(object->add_instance());
|
||||
#else /* AUTOPLACEMENT_ON_LOAD */
|
||||
// if object has no defined position(s) we need to rearrange everything after loading object->center_around_origin();
|
||||
need_arrange = true;
|
||||
// add a default instance and center object around origin
|
||||
object->center_around_origin(); // also aligns object to Z = 0
|
||||
ModelInstance* instance = object->add_instance();
|
||||
instance->set_offset(Slic3r::to_3d(bed_shape.center().cast<double>(), -object->origin_translation(2)));
|
||||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
}
|
||||
|
||||
const Vec3d size = object->bounding_box().size();
|
||||
|
@ -1513,6 +1529,18 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
// print.add_model_object(object);
|
||||
}
|
||||
|
||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||
// FIXME distance should be a config value /////////////////////////////////
|
||||
auto min_obj_distance = static_cast<coord_t>(6/SCALING_FACTOR);
|
||||
const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
|
||||
assert(bed_shape_opt);
|
||||
auto& bedpoints = bed_shape_opt->values;
|
||||
Polyline bed; bed.points.reserve(bedpoints.size());
|
||||
for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1)));
|
||||
|
||||
arr::find_new_position(model, new_instances, min_obj_distance, bed);
|
||||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
|
||||
if (scaled_down) {
|
||||
GUI::show_info(q,
|
||||
_(L("Your object appears to be too large, so it was automatically scaled down to fit your print bed.")),
|
||||
|
@ -2094,7 +2122,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx)
|
|||
o->clear_instances();
|
||||
for (auto instance: model_object->instances)
|
||||
o->add_instance(*instance);
|
||||
// o->invalidate_bounding_box();
|
||||
o->invalidate_bounding_box();
|
||||
|
||||
if (o->volumes.size() == model_object->volumes.size()) {
|
||||
for (int i = 0; i < o->volumes.size(); i++) {
|
||||
|
|
|
@ -87,6 +87,7 @@ void PreferencesDialog::build()
|
|||
option = Option (def,"show_incompatible_presets");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
// TODO: remove?
|
||||
def.label = L("Use legacy OpenGL 1.1 rendering");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If you have rendering issues caused by a buggy OpenGL 2.0 driver, "
|
||||
|
@ -96,6 +97,16 @@ void PreferencesDialog::build()
|
|||
option = Option (def,"use_legacy_opengl");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
#if __APPLE__
|
||||
def.label = L("Use Retina resolution for the 3D scene");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If enabled, the 3D scene will be rendered in Retina resolution. "
|
||||
"If you are experiencing 3D performance problems, disabling this option may help.");
|
||||
def.default_value = new ConfigOptionBool{ app_config->get("use_retina_opengl") == "1" };
|
||||
option = Option (def, "use_retina_opengl");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
#endif
|
||||
|
||||
auto sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(m_optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
|
||||
|
@ -110,8 +121,8 @@ void PreferencesDialog::build()
|
|||
|
||||
void PreferencesDialog::accept()
|
||||
{
|
||||
if (m_values.find("no_defaults") != m_values.end()||
|
||||
m_values.find("use_legacy_opengl")!= m_values.end()) {
|
||||
if (m_values.find("no_defaults") != m_values.end() ||
|
||||
m_values.find("use_legacy_opengl") != m_values.end()) {
|
||||
warning_catcher(this, _(L("You need to restart Slic3r to make the changes effective.")));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue