Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_project_dirty_state

This commit is contained in:
enricoturri1966 2021-05-03 16:05:22 +02:00
commit ede14251b1
199 changed files with 11027 additions and 6477 deletions

View file

@ -113,7 +113,7 @@ void Bed3D::Axes::render() const
glsafe(::glPopMatrix());
};
m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
const_cast<GLModel*>(&m_arrow)->init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
@ -143,13 +143,6 @@ void Bed3D::Axes::render() const
glsafe(::glDisable(GL_DEPTH_TEST));
}
Bed3D::Bed3D()
: m_type(Custom)
, m_vbo_id(0)
, m_scale_factor(1.0f)
{
}
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
{
auto check_texture = [](const std::string& texture) {
@ -193,7 +186,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
ExPolygon poly;
for (const Vec2d& p : m_shape) {
poly.contour.append(Point(scale_(p(0)), scale_(p(1))));
poly.contour.append({ scale_(p(0)), scale_(p(1)) });
}
calc_triangles(poly);
@ -201,7 +194,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
const BoundingBox& bed_bbox = poly.contour.bounding_box();
calc_gridlines(poly, bed_bbox);
m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour;
m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0];
reset();
m_texture.reset();
@ -228,7 +221,8 @@ Point Bed3D::point_projection(const Point& point) const
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
bool show_axes, bool show_texture) const
{
m_scale_factor = scale_factor;
float* factor = const_cast<float*>(&m_scale_factor);
*factor = scale_factor;
if (show_axes)
render_axes();
@ -247,22 +241,24 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
void Bed3D::calc_bounding_boxes() const
{
m_bounding_box = BoundingBoxf3();
BoundingBoxf3* bounding_box = const_cast<BoundingBoxf3*>(&m_bounding_box);
*bounding_box = BoundingBoxf3();
for (const Vec2d& p : m_shape) {
m_bounding_box.merge(Vec3d(p(0), p(1), 0.0));
bounding_box->merge({ p(0), p(1), 0.0 });
}
m_extended_bounding_box = m_bounding_box;
BoundingBoxf3* extended_bounding_box = const_cast<BoundingBoxf3*>(&m_extended_bounding_box);
*extended_bounding_box = m_bounding_box;
// extend to contain axes
m_extended_bounding_box.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
m_extended_bounding_box.merge(m_extended_bounding_box.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, m_extended_bounding_box.max(2)));
extended_bounding_box->merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
extended_bounding_box->merge(extended_bounding_box->min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, extended_bounding_box->max(2)));
// extend to contain model, if any
BoundingBoxf3 model_bb = m_model.get_bounding_box();
if (model_bb.defined) {
model_bb.translate(m_model_offset);
m_extended_bounding_box.merge(model_bb);
extended_bounding_box->merge(model_bb);
}
}
@ -339,21 +335,24 @@ void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) co
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
{
GLTexture* texture = const_cast<GLTexture*>(&m_texture);
GLTexture* temp_texture = const_cast<GLTexture*>(&m_temp_texture);
if (m_texture_filename.empty()) {
m_texture.reset();
texture->reset();
render_default(bottom);
return;
}
if ((m_texture.get_id() == 0) || (m_texture.get_source() != m_texture_filename)) {
m_texture.reset();
if (texture->get_id() == 0 || texture->get_source() != m_texture_filename) {
texture->reset();
if (boost::algorithm::iends_with(m_texture_filename, ".svg")) {
// use higher resolution images if graphic card and opengl version allow
GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size();
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) {
if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) {
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) {
if (!temp_texture->load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) {
render_default(bottom);
return;
}
@ -361,15 +360,15 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
}
// starts generating the main texture, compression will run asynchronously
if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) {
if (!texture->load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) {
render_default(bottom);
return;
}
}
else if (boost::algorithm::iends_with(m_texture_filename, ".png")) {
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) {
if (!m_temp_texture.load_from_file(m_texture_filename, false, GLTexture::None, false)) {
if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) {
if (!temp_texture->load_from_file(m_texture_filename, false, GLTexture::None, false)) {
render_default(bottom);
return;
}
@ -377,7 +376,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
}
// starts generating the main texture, compression will run asynchronously
if (!m_texture.load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) {
if (!texture->load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) {
render_default(bottom);
return;
}
@ -387,13 +386,13 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
return;
}
}
else if (m_texture.unsent_compressed_data_available()) {
else if (texture->unsent_compressed_data_available()) {
// sends to gpu the already available compressed levels of the main texture
m_texture.send_compressed_data_to_gpu();
texture->send_compressed_data_to_gpu();
// the temporary texture is not needed anymore, reset it
if (m_temp_texture.get_id() != 0)
m_temp_texture.reset();
if (temp_texture->get_id() != 0)
temp_texture->reset();
canvas.request_extra_frame();
@ -406,9 +405,11 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
shader->set_uniform("transparent_background", bottom);
shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg"));
if (m_vbo_id == 0) {
glsafe(::glGenBuffers(1, &m_vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
unsigned int* vbo_id = const_cast<unsigned int*>(&m_vbo_id);
if (*vbo_id == 0) {
glsafe(::glGenBuffers(1, vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
@ -428,12 +429,12 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
GLint tex_coords_id = shader->get_attrib_location("v_tex_coords");
// show the temporary texture while no compressed data is available
GLuint tex_id = (GLuint)m_temp_texture.get_id();
GLuint tex_id = (GLuint)temp_texture->get_id();
if (tex_id == 0)
tex_id = (GLuint)m_texture.get_id();
tex_id = (GLuint)texture->get_id();
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id));
if (position_id != -1) {
glsafe(::glEnableVertexAttribArray(position_id));
@ -471,24 +472,26 @@ void Bed3D::render_model() const
if (m_model_filename.empty())
return;
if ((m_model.get_filename() != m_model_filename) && m_model.init_from_file(m_model_filename)) {
GLModel* model = const_cast<GLModel*>(&m_model);
if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) {
// move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad
Vec3d shift = m_bounding_box.center();
shift(2) = -0.03;
m_model_offset = shift;
*const_cast<Vec3d*>(&m_model_offset) = shift;
// update extended bounding box
calc_bounding_boxes();
}
if (!m_model.get_filename().empty()) {
if (!model->get_filename().empty()) {
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader != nullptr) {
shader->start_using();
shader->set_uniform("uniform_color", m_model_color);
::glPushMatrix();
::glTranslated(m_model_offset(0), m_model_offset(1), m_model_offset(2));
m_model.render();
model->render();
::glPopMatrix();
shader->stop_using();
}
@ -511,7 +514,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) co
void Bed3D::render_default(bool bottom) const
{
m_texture.reset();
const_cast<GLTexture*>(&m_texture)->reset();
unsigned int triangles_vcount = m_triangles.get_vertices_count();
if (triangles_vcount > 0) {

View file

@ -48,7 +48,7 @@ class Bed3D
private:
Vec3d m_origin{ Vec3d::Zero() };
float m_stem_length{ DefaultStemLength };
mutable GLModel m_arrow;
GLModel m_arrow;
public:
const Vec3d& get_origin() const { return m_origin; }
@ -67,28 +67,28 @@ public:
};
private:
EType m_type;
EType m_type{ Custom };
Pointfs m_shape;
std::string m_texture_filename;
std::string m_model_filename;
mutable BoundingBoxf3 m_bounding_box;
mutable BoundingBoxf3 m_extended_bounding_box;
BoundingBoxf3 m_bounding_box;
BoundingBoxf3 m_extended_bounding_box;
Polygon m_polygon;
GeometryBuffer m_triangles;
GeometryBuffer m_gridlines;
mutable GLTexture m_texture;
mutable GLModel m_model;
mutable Vec3d m_model_offset{ Vec3d::Zero() };
std::array<float, 4> m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f };
GLTexture m_texture;
// temporary texture shown until the main texture has still no levels compressed
mutable GLTexture m_temp_texture;
mutable unsigned int m_vbo_id;
GLTexture m_temp_texture;
GLModel m_model;
Vec3d m_model_offset{ Vec3d::Zero() };
std::array<float, 4> m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f };
unsigned int m_vbo_id{ 0 };
Axes m_axes;
mutable float m_scale_factor;
float m_scale_factor{ 1.0f };
public:
Bed3D();
Bed3D() = default;
~Bed3D() { reset(); }
EType get_type() const { return m_type; }

View file

@ -421,20 +421,24 @@ const BoundingBoxf3& GLVolume::transformed_bounding_box() const
const BoundingBoxf3& box = bounding_box();
assert(box.defined || box.min(0) >= box.max(0) || box.min(1) >= box.max(1) || box.min(2) >= box.max(2));
if (m_transformed_bounding_box_dirty)
{
m_transformed_bounding_box = box.transformed(world_matrix());
m_transformed_bounding_box_dirty = false;
BoundingBoxf3* transformed_bounding_box = const_cast<BoundingBoxf3*>(&m_transformed_bounding_box);
bool* transformed_bounding_box_dirty = const_cast<bool*>(&m_transformed_bounding_box_dirty);
if (*transformed_bounding_box_dirty) {
*transformed_bounding_box = box.transformed(world_matrix());
*transformed_bounding_box_dirty = false;
}
return m_transformed_bounding_box;
return *transformed_bounding_box;
}
const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
{
if (m_transformed_convex_hull_bounding_box_dirty)
m_transformed_convex_hull_bounding_box = this->transformed_convex_hull_bounding_box(world_matrix());
return m_transformed_convex_hull_bounding_box;
BoundingBoxf3* transformed_convex_hull_bounding_box = const_cast<BoundingBoxf3*>(&m_transformed_convex_hull_bounding_box);
bool* transformed_convex_hull_bounding_box_dirty = const_cast<bool*>(&m_transformed_convex_hull_bounding_box_dirty);
if (*transformed_convex_hull_bounding_box_dirty) {
*transformed_convex_hull_bounding_box = this->transformed_convex_hull_bounding_box(world_matrix());
*transformed_convex_hull_bounding_box_dirty = false;
}
return *transformed_convex_hull_bounding_box;
}
BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const
@ -795,7 +799,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
glsafe(::glDisable(GL_BLEND));
}
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state)
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const
{
if (config == nullptr)
return false;
@ -805,7 +809,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
return false;
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height")));
BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0 }, { unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height") });
// Allow the objects to protrude below the print bed
print_volume.min(2) = -1e10;
print_volume.min(0) -= BedEpsilon;
@ -817,9 +821,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
bool contained_min_one = false;
for (GLVolume* volume : this->volumes)
{
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
for (GLVolume* volume : this->volumes) {
if (volume == nullptr || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || (volume->composite_id.volume_id < 0 && !volume->shader_outside_printer_detection_enabled))
continue;
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
@ -832,10 +835,10 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
if (contained)
contained_min_one = true;
if ((state == ModelInstancePVS_Inside) && volume->is_outside)
if (state == ModelInstancePVS_Inside && volume->is_outside)
state = ModelInstancePVS_Fully_Outside;
if ((state == ModelInstancePVS_Fully_Outside) && volume->is_outside && print_volume.intersects(bb))
if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb))
state = ModelInstancePVS_Partly_Outside;
}
@ -845,7 +848,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
return contained_min_one;
}
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut)
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut) const
{
if (config == nullptr)
return false;
@ -867,9 +870,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, b
partlyOut = false;
fullyOut = false;
for (GLVolume* volume : this->volumes)
{
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
for (GLVolume* volume : this->volumes) {
if (volume == nullptr || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || (volume->composite_id.volume_id < 0 && !volume->shader_outside_printer_detection_enabled))
continue;
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();

View file

@ -267,15 +267,15 @@ private:
// Shift in z required by sla supports+pad
double m_sla_shift_z;
// Bounding box of this volume, in unscaled coordinates.
mutable BoundingBoxf3 m_transformed_bounding_box;
BoundingBoxf3 m_transformed_bounding_box;
// Whether or not is needed to recalculate the transformed bounding box.
mutable bool m_transformed_bounding_box_dirty;
bool m_transformed_bounding_box_dirty;
// Convex hull of the volume, if any.
std::shared_ptr<const TriangleMesh> m_convex_hull;
// Bounding box of this volume, in unscaled coordinates.
mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box;
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;
bool m_transformed_convex_hull_bounding_box_dirty;
public:
// Color of the triangles / quads held by this volume.
@ -568,8 +568,8 @@ public:
// returns true if all the volumes are completely contained in the print volume
// returns the containment state in the given out_state, if non-null
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state);
bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut);
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const;
bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut) const;
void reset_outside_state();
void update_colors_by_extruder(const DynamicPrintConfig* config);

View file

@ -21,12 +21,6 @@ double Camera::FrustrumMinNearZ = 100.0;
double Camera::FrustrumZMargin = 10.0;
double Camera::MaxFovDeg = 60.0;
Camera::Camera()
: requires_zoom_to_bed(false)
{
set_default_orientation();
}
std::string Camera::get_type_as_string() const
{
switch (m_type)
@ -49,11 +43,6 @@ void Camera::set_type(EType type)
}
}
void Camera::set_type(const std::string& type)
{
set_type((type == "1") ? Perspective : Ortho);
}
void Camera::select_next_type()
{
unsigned char next = (unsigned char)m_type + 1;
@ -65,24 +54,18 @@ void Camera::select_next_type()
void Camera::set_target(const Vec3d& target)
{
Vec3d new_target = validate_target(target);
Vec3d new_displacement = new_target - m_target;
if (!new_displacement.isApprox(Vec3d::Zero()))
{
const Vec3d new_target = validate_target(target);
const Vec3d new_displacement = new_target - m_target;
if (!new_displacement.isApprox(Vec3d::Zero())) {
m_target = new_target;
m_view_matrix.translate(-new_displacement);
}
}
void Camera::update_zoom(double delta_zoom)
{
set_zoom(m_zoom / (1.0 - std::max(std::min(delta_zoom, 4.0), -4.0) * 0.1));
}
void Camera::set_zoom(double zoom)
{
// Don't allow to zoom too far outside the scene.
double zoom_min = min_zoom();
const double zoom_min = min_zoom();
if (zoom_min > 0.0)
zoom = std::max(zoom, zoom_min);
@ -123,7 +106,7 @@ double Camera::get_fov() const
void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const
{
glsafe(::glViewport(0, 0, w, h));
glsafe(::glGetIntegerv(GL_VIEWPORT, m_viewport.data()));
glsafe(::glGetIntegerv(GL_VIEWPORT, const_cast<std::array<int, 4>*>(&m_viewport)->data()));
}
void Camera::apply_view_matrix() const
@ -138,22 +121,23 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
double w = 0.0;
double h = 0.0;
double old_distance = m_distance;
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
const double old_distance = m_distance;
std::pair<double, double>* frustrum_zs = const_cast<std::pair<double, double>*>(&m_frustrum_zs);
*frustrum_zs = calc_tight_frustrum_zs_around(box);
if (m_distance != old_distance)
// the camera has been moved re-apply view matrix
apply_view_matrix();
if (near_z > 0.0)
m_frustrum_zs.first = std::max(std::min(m_frustrum_zs.first, near_z), FrustrumMinNearZ);
frustrum_zs->first = std::max(std::min(frustrum_zs->first, near_z), FrustrumMinNearZ);
if (far_z > 0.0)
m_frustrum_zs.second = std::max(m_frustrum_zs.second, far_z);
frustrum_zs->second = std::max(frustrum_zs->second, far_z);
w = 0.5 * (double)m_viewport[2];
h = 0.5 * (double)m_viewport[3];
double inv_zoom = get_inv_zoom();
const double inv_zoom = get_inv_zoom();
w *= inv_zoom;
h *= inv_zoom;
@ -162,16 +146,16 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
default:
case Ortho:
{
m_gui_scale = 1.0;
*const_cast<double*>(&m_gui_scale) = 1.0;
break;
}
case Perspective:
{
// scale near plane to keep w and h constant on the plane at z = m_distance
double scale = m_frustrum_zs.first / m_distance;
const double scale = frustrum_zs->first / m_distance;
w *= scale;
h *= scale;
m_gui_scale = scale;
*const_cast<double*>(&m_gui_scale) = scale;
break;
}
}
@ -184,26 +168,25 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
default:
case Ortho:
{
glsafe(::glOrtho(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second));
glsafe(::glOrtho(-w, w, -h, h, frustrum_zs->first, frustrum_zs->second));
break;
}
case Perspective:
{
glsafe(::glFrustum(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second));
glsafe(::glFrustum(-w, w, -h, h, frustrum_zs->first, frustrum_zs->second));
break;
}
}
glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data()));
glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, const_cast<Transform3d*>(&m_projection_matrix)->data()));
glsafe(::glMatrixMode(GL_MODELVIEW));
}
void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor)
{
// Calculate the zoom factor needed to adjust the view around the given box.
double zoom = calc_zoom_to_bounding_box_factor(box, margin_factor);
if (zoom > 0.0)
{
const double zoom = calc_zoom_to_bounding_box_factor(box, margin_factor);
if (zoom > 0.0) {
m_zoom = zoom;
// center view around box center
set_target(box.center());
@ -213,9 +196,8 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor)
void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor)
{
Vec3d center;
double zoom = calc_zoom_to_volumes_factor(volumes, center, margin_factor);
if (zoom > 0.0)
{
const double zoom = calc_zoom_to_volumes_factor(volumes, center, margin_factor);
if (zoom > 0.0) {
m_zoom = zoom;
// center view around the calculated center
set_target(center);
@ -289,8 +271,8 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
}
}
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
const Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
const auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
m_view_rotation *= rot_z * Eigen::AngleAxisd(delta_zenit_rad, rot_z.inverse() * get_dir_right());
m_view_rotation.normalize();
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
@ -299,10 +281,10 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
// Virtual trackball, rotate around an axis, where the eucledian norm of the axis gives the rotation angle in radians.
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
{
double angle = rotation_rad.norm();
const double angle = rotation_rad.norm();
if (std::abs(angle) > EPSILON) {
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
const Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
const Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
m_view_rotation *= Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis));
m_view_rotation.normalize();
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (-m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
@ -310,18 +292,13 @@ void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
}
}
double Camera::min_zoom() const
{
return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box);
}
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
{
std::pair<double, double> ret;
auto& [near_z, far_z] = ret;
// box in eye space
BoundingBoxf3 eye_box = box.transformed(m_view_matrix);
const BoundingBoxf3 eye_box = box.transformed(m_view_matrix);
near_z = -eye_box.max(2);
far_z = -eye_box.min(2);
@ -330,73 +307,71 @@ std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBo
far_z += FrustrumZMargin;
// ensure min size
if (far_z - near_z < FrustrumMinZRange)
{
double mid_z = 0.5 * (near_z + far_z);
double half_size = 0.5 * FrustrumMinZRange;
if (far_z - near_z < FrustrumMinZRange) {
const double mid_z = 0.5 * (near_z + far_z);
const double half_size = 0.5 * FrustrumMinZRange;
near_z = mid_z - half_size;
far_z = mid_z + half_size;
}
if (near_z < FrustrumMinNearZ)
{
float delta = FrustrumMinNearZ - near_z;
if (near_z < FrustrumMinNearZ) {
const double delta = FrustrumMinNearZ - near_z;
set_distance(m_distance + delta);
near_z += delta;
far_z += delta;
}
else if ((near_z > 2.0 * FrustrumMinNearZ) && (m_distance > DefaultDistance))
{
float delta = m_distance - DefaultDistance;
set_distance(DefaultDistance);
near_z -= delta;
far_z -= delta;
}
// The following is commented out because it causes flickering of the 3D scene GUI
// when the bounding box of the scene gets large enough
// We need to introduce some smarter code to move the camera back and forth in such case
// else if (near_z > 2.0 * FrustrumMinNearZ && m_distance > DefaultDistance) {
// float delta = m_distance - DefaultDistance;
// set_distance(DefaultDistance);
// near_z -= delta;
// far_z -= delta;
// }
return ret;
}
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor) const
{
double max_bb_size = box.max_size();
const double max_bb_size = box.max_size();
if (max_bb_size == 0.0)
return -1.0;
// project the box vertices on a plane perpendicular to the camera forward axis
// then calculates the vertices coordinate on this plane along the camera xy axes
Vec3d right = get_dir_right();
Vec3d up = get_dir_up();
Vec3d forward = get_dir_forward();
Vec3d bb_center = box.center();
const Vec3d right = get_dir_right();
const Vec3d up = get_dir_up();
const Vec3d forward = get_dir_forward();
const Vec3d bb_center = box.center();
// box vertices in world space
std::vector<Vec3d> vertices;
vertices.reserve(8);
vertices.push_back(box.min);
vertices.emplace_back(box.max(0), box.min(1), box.min(2));
vertices.emplace_back(box.max(0), box.max(1), box.min(2));
vertices.emplace_back(box.min(0), box.max(1), box.min(2));
vertices.emplace_back(box.min(0), box.min(1), box.max(2));
vertices.emplace_back(box.max(0), box.min(1), box.max(2));
vertices.push_back(box.max);
vertices.emplace_back(box.min(0), box.max(1), box.max(2));
const std::vector<Vec3d> vertices = {
box.min,
{ box.max(0), box.min(1), box.min(2) },
{ box.max(0), box.max(1), box.min(2) },
{ box.min(0), box.max(1), box.min(2) },
{ box.min(0), box.min(1), box.max(2) },
{ box.max(0), box.min(1), box.max(2) },
box.max,
{ box.min(0), box.max(1), box.max(2) }
};
double min_x = DBL_MAX;
double min_y = DBL_MAX;
double max_x = -DBL_MAX;
double max_y = -DBL_MAX;
for (const Vec3d& v : vertices)
{
for (const Vec3d& v : vertices) {
// project vertex on the plane perpendicular to camera forward axis
Vec3d pos = v - bb_center;
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
const Vec3d pos = v - bb_center;
const Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
// calculates vertex coordinate along camera xy axes
double x_on_plane = proj_on_plane.dot(right);
double y_on_plane = proj_on_plane.dot(up);
const double x_on_plane = proj_on_plane.dot(right);
const double y_on_plane = proj_on_plane.dot(up);
min_x = std::min(min_x, x_on_plane);
min_y = std::min(min_y, y_on_plane);
@ -406,7 +381,7 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double
double dx = max_x - min_x;
double dy = max_y - min_y;
if ((dx <= 0.0) || (dy <= 0.0))
if (dx <= 0.0 || dy <= 0.0)
return -1.0f;
dx *= margin_factor;
@ -423,13 +398,12 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
// project the volumes vertices on a plane perpendicular to the camera forward axis
// then calculates the vertices coordinate on this plane along the camera xy axes
Vec3d right = get_dir_right();
Vec3d up = get_dir_up();
Vec3d forward = get_dir_forward();
const Vec3d right = get_dir_right();
const Vec3d up = get_dir_up();
const Vec3d forward = get_dir_forward();
BoundingBoxf3 box;
for (const GLVolume* volume : volumes)
{
for (const GLVolume* volume : volumes) {
box.merge(volume->transformed_bounding_box());
}
center = box.center();
@ -439,24 +413,22 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
double max_x = -DBL_MAX;
double max_y = -DBL_MAX;
for (const GLVolume* volume : volumes)
{
for (const GLVolume* volume : volumes) {
const Transform3d& transform = volume->world_matrix();
const TriangleMesh* hull = volume->convex_hull();
if (hull == nullptr)
continue;
for (const Vec3f& vertex : hull->its.vertices)
{
Vec3d v = transform * vertex.cast<double>();
for (const Vec3f& vertex : hull->its.vertices) {
const Vec3d v = transform * vertex.cast<double>();
// project vertex on the plane perpendicular to camera forward axis
Vec3d pos = v - center;
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
const Vec3d pos = v - center;
const Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
// calculates vertex coordinate along camera xy axes
double x_on_plane = proj_on_plane.dot(right);
double y_on_plane = proj_on_plane.dot(up);
const double x_on_plane = proj_on_plane.dot(right);
const double y_on_plane = proj_on_plane.dot(up);
min_x = std::min(min_x, x_on_plane);
min_y = std::min(min_y, y_on_plane);
@ -467,10 +439,10 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
center += 0.5 * (max_x + min_x) * right + 0.5 * (max_y + min_y) * up;
double dx = margin_factor * (max_x - min_x);
double dy = margin_factor * (max_y - min_y);
const double dx = margin_factor * (max_x - min_x);
const double dy = margin_factor * (max_y - min_y);
if ((dx <= 0.0) || (dy <= 0.0))
if (dx <= 0.0 || dy <= 0.0)
return -1.0f;
return std::min((double)m_viewport[2] / dx, (double)m_viewport[3] / dy);
@ -478,22 +450,21 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
void Camera::set_distance(double distance) const
{
if (m_distance != distance)
{
m_view_matrix.translate((distance - m_distance) * get_dir_forward());
m_distance = distance;
if (m_distance != distance) {
const_cast<Transform3d*>(&m_view_matrix)->translate((distance - m_distance) * get_dir_forward());
*const_cast<double*>(&m_distance) = distance;
}
}
void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up)
{
Vec3d unit_z = (position - target).normalized();
Vec3d unit_x = up.cross(unit_z).normalized();
Vec3d unit_y = unit_z.cross(unit_x).normalized();
const Vec3d unit_z = (position - target).normalized();
const Vec3d unit_x = up.cross(unit_z).normalized();
const Vec3d unit_y = unit_z.cross(unit_x).normalized();
m_target = target;
m_distance = (position - target).norm();
Vec3d new_position = m_target + m_distance * unit_z;
const Vec3d new_position = m_target + m_distance * unit_z;
m_view_matrix(0, 0) = unit_x(0);
m_view_matrix(0, 1) = unit_x(1);
@ -525,10 +496,10 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up
void Camera::set_default_orientation()
{
m_zenit = 45.0f;
double theta_rad = Geometry::deg2rad(-(double)m_zenit);
double phi_rad = Geometry::deg2rad(45.0);
double sin_theta = ::sin(theta_rad);
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
const double theta_rad = Geometry::deg2rad(-(double)m_zenit);
const double phi_rad = Geometry::deg2rad(45.0);
const double sin_theta = ::sin(theta_rad);
const Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
m_view_rotation = Eigen::AngleAxisd(theta_rad, Vec3d::UnitX()) * Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ());
m_view_rotation.normalize();
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- camera_pos), m_view_rotation, Vec3d(1., 1., 1.));
@ -543,9 +514,9 @@ Vec3d Camera::validate_target(const Vec3d& target) const
test_box.scale(ScaleFactor);
test_box.translate(m_scene_box.center());
return Vec3d(std::clamp(target(0), test_box.min(0), test_box.max(0)),
std::clamp(target(1), test_box.min(1), test_box.max(1)),
std::clamp(target(2), test_box.min(2), test_box.max(2)));
return { std::clamp(target(0), test_box.min(0), test_box.max(0)),
std::clamp(target(1), test_box.min(1), test_box.max(1)),
std::clamp(target(2), test_box.min(2), test_box.max(2)) };
}
void Camera::update_zenit()

View file

@ -26,7 +26,7 @@ struct Camera
Num_types
};
bool requires_zoom_to_bed;
bool requires_zoom_to_bed{ false };
private:
EType m_type{ Perspective };
@ -35,26 +35,26 @@ private:
float m_zenit{ 45.0f };
double m_zoom{ 1.0 };
// Distance between camera position and camera target measured along the camera Z axis
mutable double m_distance{ DefaultDistance };
mutable double m_gui_scale{ 1.0 };
double m_distance{ DefaultDistance };
double m_gui_scale{ 1.0 };
mutable std::array<int, 4> m_viewport;
mutable Transform3d m_view_matrix{ Transform3d::Identity() };
std::array<int, 4> m_viewport;
Transform3d m_view_matrix{ Transform3d::Identity() };
// We are calculating the rotation part of the m_view_matrix from m_view_rotation.
mutable Eigen::Quaterniond m_view_rotation{ 1.0, 0.0, 0.0, 0.0 };
mutable Transform3d m_projection_matrix{ Transform3d::Identity() };
mutable std::pair<double, double> m_frustrum_zs;
Eigen::Quaterniond m_view_rotation{ 1.0, 0.0, 0.0, 0.0 };
Transform3d m_projection_matrix{ Transform3d::Identity() };
std::pair<double, double> m_frustrum_zs;
BoundingBoxf3 m_scene_box;
public:
Camera();
Camera() { set_default_orientation(); }
EType get_type() const { return m_type; }
std::string get_type_as_string() const;
void set_type(EType type);
// valid values for type: "0" -> ortho, "1" -> perspective
void set_type(const std::string& type);
void set_type(const std::string& type) { set_type((type == "1") ? Perspective : Ortho); }
void select_next_type();
void enable_update_config_on_type_change(bool enable) { m_update_config_on_type_change_enabled = enable; }
@ -67,7 +67,7 @@ public:
double get_zoom() const { return m_zoom; }
double get_inv_zoom() const { assert(m_zoom != 0.0); return 1.0 / m_zoom; }
void update_zoom(double delta_zoom);
void update_zoom(double delta_zoom) { set_zoom(m_zoom / (1.0 - std::max(std::min(delta_zoom, 4.0), -4.0) * 0.1)); }
void set_zoom(double zoom);
const BoundingBoxf3& get_scene_box() const { return m_scene_box; }
@ -119,8 +119,7 @@ public:
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
// forces camera right vector to be parallel to XY plane
void recover_from_free_camera()
{
void recover_from_free_camera() {
if (std::abs(get_dir_right()(2)) > EPSILON)
look_at(get_position(), m_target, Vec3d::UnitZ());
}
@ -128,7 +127,7 @@ public:
void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
double max_zoom() const { return 250.0; }
double min_zoom() const;
double min_zoom() const { return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box); }
private:
// returns tight values for nearZ and farZ plane around the given bounding box

View file

@ -45,7 +45,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
// layer_height shouldn't be equal to zero
if (config->opt_float("layer_height") < EPSILON)
{
const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01."));
const wxString msg_text = _(L("Layer height is not valid.\n\nThe layer height will be reset to 0.01."));
wxMessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@ -55,9 +55,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
is_msg_dlg_already_exist = false;
}
if (fabs(config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value - 0) < EPSILON)
if (config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value < EPSILON)
{
const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
const wxString msg_text = _(L("First layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
wxMessageDialog dialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@ -278,6 +278,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto");
bool have_support_interface = config->opt_int("support_material_interface_layers") > 0;
bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0;
auto support_material_style = config->opt_enum<SupportMaterialStyle>("support_material_style");
for (auto el : { "support_material_style", "support_material_pattern", "support_material_with_sheath",
"support_material_spacing", "support_material_angle",
"support_material_interface_pattern", "support_material_interface_layers",
@ -286,6 +287,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field(el, have_support_material);
toggle_field("support_material_threshold", have_support_material_auto);
toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble);
toggle_field("support_material_closing_radius", have_support_material && support_material_style == smsSnug);
for (auto el : { "support_material_bottom_interface_layers", "support_material_interface_spacing", "support_material_interface_extruder",
"support_material_interface_speed", "support_material_interface_contact_loops" })

View file

@ -29,11 +29,20 @@ static wxString format_reason(const Config::Snapshot::Reason reason)
}
}
static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_even, bool snapshot_active)
static std::string get_color(wxColour colour)
{
wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue());
return clr_str.ToStdString();
};
static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_even, bool snapshot_active, bool dark_mode)
{
// Start by declaring a row with an alternating background color.
wxString text = "<tr bgcolor=\"";
text += snapshot_active ? "#B3FFCB" : (row_even ? "#FFFFFF" : "#D5D5D5");
text += snapshot_active ?
dark_mode ? "#208a20" : "#B3FFCB" :
(row_even ? get_color(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) : dark_mode ? "#656565" : "#D5D5D5" );
text += "\">";
text += "<td>";
@ -92,14 +101,15 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
static wxString generate_html_page(const Config::SnapshotDB &snapshot_db, const wxString &on_snapshot)
{
bool dark_mode = wxGetApp().dark_mode();
wxString text =
"<html>"
"<body bgcolor=\"#ffffff\" cellspacing=\"2\" cellpadding=\"0\" border=\"0\" link=\"#800000\">"
"<font color=\"#000000\">";
"<body bgcolor=\"" + get_color(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) + "\" cellspacing=\"2\" cellpadding=\"0\" border=\"0\" link=\"#800000\">"
"<font color=\"" + get_color(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)) + "\">";
text += "<table style=\"width:100%\">";
for (size_t i_row = 0; i_row < snapshot_db.snapshots().size(); ++ i_row) {
const Config::Snapshot &snapshot = snapshot_db.snapshots()[snapshot_db.snapshots().size() - i_row - 1];
text += generate_html_row(snapshot, i_row & 1, snapshot.id == on_snapshot);
text += generate_html_row(snapshot, i_row & 1, snapshot.id == on_snapshot, dark_mode);
}
text +=
"</table>"
@ -115,8 +125,8 @@ ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
{
this->SetFont(wxGetApp().normal_font());
this->SetBackgroundColour(*wxWHITE);
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
this->SetSizer(vsizer);

View file

@ -2165,7 +2165,7 @@ static std::string get_custom_code(const std::string& code_in, double height)
if (dlg.ShowModal() != wxID_OK)
return "";
value = dlg.GetValue().ToStdString();
value = into_u8(dlg.GetValue());
valid = GUI::Tab::validate_custom_gcode("Custom G-code", value);
} while (!valid);
return value;
@ -2173,7 +2173,7 @@ static std::string get_custom_code(const std::string& code_in, double height)
if (dlg.ShowModal() != wxID_OK)
return "";
return dlg.GetValue().ToStdString();
return into_u8(dlg.GetValue());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
}

View file

@ -143,6 +143,9 @@ bool GCodeViewer::Path::matches(const GCodeProcessor::MoveVertex& move) const
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
#if ENABLE_SEAMS_VISUALIZATION
case EMoveType::Seam:
#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Extrude: {
// use rounding to reduce the number of generated paths
#if ENABLE_SPLITTED_VERTEX_BUFFER
@ -540,6 +543,9 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
const std::vector<GCodeViewer::Color> GCodeViewer::Options_Colors {{
{ 0.803f, 0.135f, 0.839f }, // Retractions
{ 0.287f, 0.679f, 0.810f }, // Unretractions
#if ENABLE_SEAMS_VISUALIZATION
{ 0.900f, 0.900f, 0.900f }, // Seams
#endif // ENABLE_SEAMS_VISUALIZATION
{ 0.758f, 0.744f, 0.389f }, // ToolChanges
{ 0.856f, 0.582f, 0.546f }, // ColorChanges
{ 0.322f, 0.942f, 0.512f }, // PausePrints
@ -582,11 +588,20 @@ GCodeViewer::GCodeViewer()
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
#if ENABLE_SEAMS_VISUALIZATION
case EMoveType::Unretract:
case EMoveType::Seam: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
break;
}
#else
case EMoveType::Unretract: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
break;
}
#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
@ -796,10 +811,18 @@ void GCodeViewer::render() const
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
#if ENABLE_SEAMS_VISUALIZATION
case EMoveType::Unretract:
case EMoveType::Seam: {
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
break;
}
#else
case EMoveType::Unretract: {
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
break;
}
#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.shader = "gouraud_light";
@ -938,6 +961,9 @@ unsigned int GCodeViewer::get_options_visibility_flags() const
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Wipe), is_toolpath_move_type_visible(EMoveType::Wipe));
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Retractions), is_toolpath_move_type_visible(EMoveType::Retract));
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Unretractions), is_toolpath_move_type_visible(EMoveType::Unretract));
#if ENABLE_SEAMS_VISUALIZATION
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Seams), is_toolpath_move_type_visible(EMoveType::Seam));
#endif // ENABLE_SEAMS_VISUALIZATION
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::ToolChanges), is_toolpath_move_type_visible(EMoveType::Tool_change));
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::ColorChanges), is_toolpath_move_type_visible(EMoveType::Color_change));
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::PausePrints), is_toolpath_move_type_visible(EMoveType::Pause_Print));
@ -958,6 +984,9 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
set_toolpath_move_type_visible(EMoveType::Wipe, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Wipe)));
set_toolpath_move_type_visible(EMoveType::Retract, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Retractions)));
set_toolpath_move_type_visible(EMoveType::Unretract, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Unretractions)));
#if ENABLE_SEAMS_VISUALIZATION
set_toolpath_move_type_visible(EMoveType::Seam, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Seams)));
#endif // ENABLE_SEAMS_VISUALIZATION
set_toolpath_move_type_visible(EMoveType::Tool_change, is_flag_set(static_cast<unsigned int>(Preview::OptionType::ToolChanges)));
set_toolpath_move_type_visible(EMoveType::Color_change, is_flag_set(static_cast<unsigned int>(Preview::OptionType::ColorChanges)));
set_toolpath_move_type_visible(EMoveType::Pause_Print, is_flag_set(static_cast<unsigned int>(Preview::OptionType::PausePrints)));
@ -1595,13 +1624,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
const std::array<IBufferType, 8> first_seg_v_offsets = convert_vertices_offset(vbuffer_size, { 0, 1, 2, 3, 4, 5, 6, 7 });
const std::array<IBufferType, 8> non_first_seg_v_offsets = convert_vertices_offset(vbuffer_size, { -4, 0, -2, 1, 2, 3, 4, 5 });
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
bool is_first_segment = (last_path.vertices_count() == 1);
if (is_first_segment || vbuffer_size == 0) {
#else
if (last_path.vertices_count() == 1 || vbuffer_size == 0) {
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// 1st segment or restart into a new vertex buffer
// ===============================================
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
if (last_path.vertices_count() == 1)
if (is_first_segment)
// starting cap triangles
append_starting_cap_triangles(indices, first_seg_v_offsets);
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
@ -1679,7 +1710,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
if (next != nullptr && (curr.type != next->type || !last_path.matches(*next)))
// ending cap triangles
append_ending_cap_triangles(indices, non_first_seg_v_offsets);
append_ending_cap_triangles(indices, is_first_segment ? first_seg_v_offsets : non_first_seg_v_offsets);
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
last_path.sub_paths.back().last = { ibuffer_id, indices.size() - 1, move_id, curr.position };
@ -1714,7 +1745,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// for the gcode viewer we need to take in account all moves to correctly size the printbed
m_paths_bounding_box.merge(move.position.cast<double>());
else {
#if ENABLE_START_GCODE_VISUALIZATION
if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f)
#else
if (move.type == EMoveType::Extrude && move.width != 0.0f && move.height != 0.0f)
#endif // ENABLE_START_GCODE_VISUALIZATION
m_paths_bounding_box.merge(move.position.cast<double>());
}
}
@ -3163,6 +3198,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
case EMoveType::Custom_GCode: { color = Options_Colors[static_cast<unsigned int>(EOptionsColors::CustomGCodes)]; break; }
case EMoveType::Retract: { color = Options_Colors[static_cast<unsigned int>(EOptionsColors::Retractions)]; break; }
case EMoveType::Unretract: { color = Options_Colors[static_cast<unsigned int>(EOptionsColors::Unretractions)]; break; }
#if ENABLE_SEAMS_VISUALIZATION
case EMoveType::Seam: { color = Options_Colors[static_cast<unsigned int>(EOptionsColors::Seams)]; break; }
#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Extrude: {
if (!top_layer_only ||
m_sequential_view.current.last == global_endpoints.last ||
@ -4557,7 +4595,12 @@ void GCodeViewer::render_legend() const
available(EMoveType::Pause_Print) ||
available(EMoveType::Retract) ||
available(EMoveType::Tool_change) ||
#if ENABLE_SEAMS_VISUALIZATION
available(EMoveType::Unretract) ||
available(EMoveType::Seam);
#else
available(EMoveType::Unretract);
#endif // ENABLE_SEAMS_VISUALIZATION
};
auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
@ -4575,6 +4618,9 @@ void GCodeViewer::render_legend() const
// items
add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions"));
add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions"));
#if ENABLE_SEAMS_VISUALIZATION
add_option(EMoveType::Seam, EOptionsColors::Seams, _u8L("Seams"));
#endif // ENABLE_SEAMS_VISUALIZATION
add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes"));
add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes"));
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses"));

View file

@ -46,6 +46,9 @@ class GCodeViewer
{
Retractions,
Unretractions,
#if ENABLE_SEAMS_VISUALIZATION
Seams,
#endif // ENABLE_SEAMS_VISUALIZATION
ToolChanges,
ColorChanges,
PausePrints,

View file

@ -1,7 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "GLCanvas3D.hpp"
#include "admesh/stl.h"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
@ -508,6 +507,7 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
m_layer_height_profile.clear();
m_layers_texture.valid = false;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
wxGetApp().obj_list()->update_info_items(last_object_id);
}
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor)
@ -517,6 +517,7 @@ void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
m_layers_texture.valid = false;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
wxGetApp().obj_list()->update_info_items(last_object_id);
}
void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params)
@ -526,6 +527,7 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas,
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
m_layers_texture.valid = false;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
wxGetApp().obj_list()->update_info_items(last_object_id);
}
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
@ -565,6 +567,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas)
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Manual edit")));
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
wxGetApp().obj_list()->update_info_items(last_object_id);
}
}
m_layer_height_profile_modified = false;
@ -1678,8 +1681,10 @@ void GLCanvas3D::render()
if (m_picking_enabled)
m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast<coord_t>());
_render_current_gizmo();
// sidebar hints need to be rendered before the gizmos because the depth buffer
// could be invalidated by the following gizmo render methods
_render_selection_sidebar_hints();
_render_current_gizmo();
#if ENABLE_RENDER_PICKING_PASS
}
#endif // ENABLE_RENDER_PICKING_PASS
@ -3529,7 +3534,7 @@ Vec2d GLCanvas3D::get_local_mouse_position() const
void GLCanvas3D::set_tooltip(const std::string& tooltip) const
{
if (m_canvas != nullptr)
m_tooltip.set_text(tooltip);
const_cast<Tooltip*>(&m_tooltip)->set_text(tooltip);
}
void GLCanvas3D::do_move(const std::string& snapshot_type)
@ -3546,22 +3551,19 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
Selection::EMode selection_mode = m_selection.get_mode();
for (const GLVolume* v : m_volumes.volumes)
{
for (const GLVolume* v : m_volumes.volumes) {
int object_idx = v->object_idx();
int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx();
std::pair<int, int> done_id(object_idx, instance_idx);
if ((0 <= object_idx) && (object_idx < (int)m_model->objects.size()))
{
if (0 <= object_idx && object_idx < (int)m_model->objects.size()) {
done.insert(done_id);
// Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr)
{
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
else if (selection_mode == Selection::Volume)
@ -3577,8 +3579,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
}
// Fixes sinking/flying instances
for (const std::pair<int, int>& i : done)
{
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
m_selection.translate(i.first, i.second, shift);
@ -3937,13 +3938,13 @@ bool GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
em *= m_retina_helper->get_scale_factor();
#endif
if (imgui->undo_redo_list(ImVec2(18 * em, 26 * em), is_undo, &string_getter, hovered, selected, m_mouse_wheel))
m_imgui_undo_redo_hovered_pos = hovered;
int* mouse_wheel = const_cast<int*>(&m_mouse_wheel);
if (imgui->undo_redo_list(ImVec2(18 * em, 26 * em), is_undo, &string_getter, hovered, selected, *mouse_wheel))
*const_cast<int*>(&m_imgui_undo_redo_hovered_pos) = hovered;
else
m_imgui_undo_redo_hovered_pos = -1;
*const_cast<int*>(&m_imgui_undo_redo_hovered_pos) = -1;
if (selected >= 0)
{
if (selected >= 0) {
is_undo ? wxGetApp().plater()->undo_to(selected) : wxGetApp().plater()->redo_to(selected);
action_taken = true;
}
@ -3984,9 +3985,10 @@ bool GLCanvas3D::_render_search_list(float pos_x) const
char *s = new char[255];
strcpy(s, search_line.empty() ? _u8L("Enter a search term").c_str() : search_line.c_str());
imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s,
sidebar.get_searcher().view_params,
selected, edited, m_mouse_wheel, wxGetApp().is_localized());
int* mouse_wheel = const_cast<int*>(&m_mouse_wheel);
imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s,
sidebar.get_searcher().view_params,
selected, edited, *mouse_wheel, wxGetApp().is_localized());
search_line = s;
delete [] s;
@ -4845,8 +4847,10 @@ void GLCanvas3D::_refresh_if_shown_on_screen()
void GLCanvas3D::_picking_pass() const
{
std::vector<int>* hover_volume_idxs = const_cast<std::vector<int>*>(&m_hover_volume_idxs);
if (m_picking_enabled && !m_mouse.dragging && m_mouse.position != Vec2d(DBL_MAX, DBL_MAX)) {
m_hover_volume_idxs.clear();
hover_volume_idxs->clear();
// Render the object for picking.
// FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing.
@ -4861,9 +4865,10 @@ void GLCanvas3D::_picking_pass() const
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
m_camera_clipping_plane = m_gizmos.get_clipping_plane();
if (m_camera_clipping_plane.is_active()) {
::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data());
ClippingPlane* camera_clipping_plane = const_cast<ClippingPlane*>(&m_camera_clipping_plane);
*camera_clipping_plane = m_gizmos.get_clipping_plane();
if (camera_clipping_plane->is_active()) {
::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)camera_clipping_plane->get_data());
::glEnable(GL_CLIP_PLANE0);
}
_render_volumes_for_picking();
@ -4889,11 +4894,11 @@ void GLCanvas3D::_picking_pass() const
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) {
// do not add the volume id if any gizmo is active and CTRL is pressed
if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL))
m_hover_volume_idxs.emplace_back(volume_id);
m_gizmos.set_hover_id(-1);
hover_volume_idxs->emplace_back(volume_id);
const_cast<GLGizmosManager*>(&m_gizmos)->set_hover_id(-1);
}
else
m_gizmos.set_hover_id(inside && (unsigned int)volume_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1);
const_cast<GLGizmosManager*>(&m_gizmos)->set_hover_id(inside && (unsigned int)volume_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1);
_update_volumes_hover_state();
}
@ -4901,12 +4906,11 @@ void GLCanvas3D::_picking_pass() const
void GLCanvas3D::_rectangular_selection_picking_pass() const
{
m_gizmos.set_hover_id(-1);
const_cast<GLGizmosManager*>(&m_gizmos)->set_hover_id(-1);
std::set<int> idxs;
if (m_picking_enabled)
{
if (m_picking_enabled) {
if (m_multisample_allowed)
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
glsafe(::glDisable(GL_MULTISAMPLE));
@ -4927,8 +4931,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
int left = (int)m_rectangle_selection.get_left();
int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top();
if ((left >= 0) && (top >= 0))
{
if (left >= 0 && top >= 0) {
#define USE_PARALLEL 1
#if USE_PARALLEL
struct Pixel
@ -4948,7 +4951,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
for (size_t i = range.begin(); i < range.end(); ++i)
if (frame[i].valid()) {
int volume_id = frame[i].id();
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) {
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) {
mutex.lock();
idxs.insert(volume_id);
mutex.unlock();
@ -4963,14 +4966,14 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
{
int px_id = 4 * i;
int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16);
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size())
idxs.insert(volume_id);
}
#endif // USE_PARALLEL
}
}
m_hover_volume_idxs.assign(idxs.begin(), idxs.end());
const_cast<std::vector<int>*>(&m_hover_volume_idxs)->assign(idxs.begin(), idxs.end());
_update_volumes_hover_state();
}
@ -5001,8 +5004,9 @@ void GLCanvas3D::_render_background() const
if (!m_volumes.empty())
use_error_color &= _is_any_volume_outside();
else {
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
use_error_color &= (test_volume.radius() > 0.0) ? !test_volume.contains(m_gcode_viewer.get_paths_bounding_box()) : false;
const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
use_error_color &= (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) ? !test_volume.contains(paths_volume) : false;
}
}
@ -5063,7 +5067,9 @@ void GLCanvas3D::_render_objects() const
glsafe(::glEnable(GL_DEPTH_TEST));
m_camera_clipping_plane = m_gizmos.get_clipping_plane();
ClippingPlane* camera_clipping_plane = const_cast<ClippingPlane*>(&m_camera_clipping_plane);
GLVolumeCollection* volumes = const_cast<GLVolumeCollection*>(&m_volumes);
*camera_clipping_plane = m_gizmos.get_clipping_plane();
if (m_picking_enabled) {
// Update the layer editing selection to the first object selected, update the current object maximum Z.
@ -5071,17 +5077,17 @@ void GLCanvas3D::_render_objects() const
if (m_config != nullptr) {
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
m_volumes.set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
m_volumes.check_outside_state(m_config, nullptr);
volumes->set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
volumes->check_outside_state(m_config, nullptr);
}
}
if (m_use_clipping_planes)
m_volumes.set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]);
volumes->set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]);
else
m_volumes.set_z_range(-FLT_MAX, FLT_MAX);
volumes->set_z_range(-FLT_MAX, FLT_MAX);
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
volumes->set_clipping_plane(camera_clipping_plane->get_data());
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
if (shader != nullptr) {
@ -5089,16 +5095,16 @@ void GLCanvas3D::_render_objects() const
if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
int object_id = m_layers_editing.last_object_id;
m_volumes.render(GLVolumeCollection::Opaque, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) {
volumes->render(GLVolumeCollection::Opaque, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) {
// Which volume to paint without the layer height profile shader?
return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
});
// Let LayersEditing handle rendering of the active object using the layer height profile shader.
m_layers_editing.render_volumes(*this, this->m_volumes);
m_layers_editing.render_volumes(*this, *volumes);
} else {
// do not cull backfaces to show broken geometry, if any
m_volumes.render(GLVolumeCollection::Opaque, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this](const GLVolume& volume) {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
// do not cull backfaces to show broken geometry, if any
volumes->render(GLVolumeCollection::Opaque, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this](const GLVolume& volume) {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
});
}
@ -5116,11 +5122,11 @@ void GLCanvas3D::_render_objects() const
}
}
m_volumes.render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix());
volumes->render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix());
shader->stop_using();
}
m_camera_clipping_plane = ClippingPlane::ClipsNothing();
*camera_clipping_plane = ClippingPlane::ClipsNothing();
}
void GLCanvas3D::_render_gcode() const
@ -5161,13 +5167,13 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() const
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
#if ENABLE_RETINA_GL
const float sc = m_retina_helper->get_scale_factor() * scale;
m_main_toolbar.set_scale(sc);
m_undoredo_toolbar.set_scale(sc);
const_cast<GLToolbar*>(&m_main_toolbar)->set_scale(sc);
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_scale(sc);
collapse_toolbar.set_scale(sc);
size *= m_retina_helper->get_scale_factor();
#else
m_main_toolbar.set_icons_size(size);
m_undoredo_toolbar.set_icons_size(size);
const_cast<GLToolbar*>(&m_main_toolbar)->set_icons_size(size);
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_icons_size(size);
collapse_toolbar.set_icons_size(size);
#endif // ENABLE_RETINA_GL
@ -5215,13 +5221,13 @@ void GLCanvas3D::_render_overlays() const
// to correctly place them
#if ENABLE_RETINA_GL
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(/*true*/);
m_main_toolbar.set_scale(scale);
m_undoredo_toolbar.set_scale(scale);
const_cast<GLToolbar*>(&m_main_toolbar)->set_scale(scale);
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_scale(scale);
wxGetApp().plater()->get_collapse_toolbar().set_scale(scale);
#else
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(/*true*/));
m_main_toolbar.set_icons_size(size);
m_undoredo_toolbar.set_icons_size(size);
const_cast<GLToolbar*>(&m_main_toolbar)->set_icons_size(size);
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_icons_size(size);
wxGetApp().plater()->get_collapse_toolbar().set_icons_size(size);
#endif // ENABLE_RETINA_GL
@ -5296,12 +5302,12 @@ void GLCanvas3D::_render_gizmos_overlay() const
#if ENABLE_RETINA_GL
// m_gizmos.set_overlay_scale(m_retina_helper->get_scale_factor());
const float scale = m_retina_helper->get_scale_factor()*wxGetApp().toolbar_icon_scale();
m_gizmos.set_overlay_scale(scale); //! #ys_FIXME_experiment
const_cast<GLGizmosManager*>(&m_gizmos)->set_overlay_scale(scale); //! #ys_FIXME_experiment
#else
// m_gizmos.set_overlay_scale(m_canvas->GetContentScaleFactor());
// m_gizmos.set_overlay_scale(wxGetApp().em_unit()*0.1f);
const float size = int(GLGizmosManager::Default_Icons_Size*wxGetApp().toolbar_icon_scale());
m_gizmos.set_overlay_icon_size(size); //! #ys_FIXME_experiment
const float size = int(GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale());
const_cast<GLGizmosManager*>(&m_gizmos)->set_overlay_icon_size(size); //! #ys_FIXME_experiment
#endif /* __WXMSW__ */
m_gizmos.render_overlay();
@ -5320,8 +5326,9 @@ void GLCanvas3D::_render_main_toolbar() const
float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f;
float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width) * inv_zoom;
m_main_toolbar.set_position(top, left);
m_main_toolbar.render(*this);
GLToolbar* main_toolbar = const_cast<GLToolbar*>(&m_main_toolbar);
main_toolbar->set_position(top, left);
main_toolbar->render(*this);
}
void GLCanvas3D::_render_undoredo_toolbar() const
@ -5336,8 +5343,10 @@ void GLCanvas3D::_render_undoredo_toolbar() const
const GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f;
float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width)) * inv_zoom;
m_undoredo_toolbar.set_position(top, left);
m_undoredo_toolbar.render(*this);
GLToolbar* undoredo_toolbar = const_cast<GLToolbar*>(&m_undoredo_toolbar);
undoredo_toolbar->set_position(top, left);
undoredo_toolbar->render(*this);
}
void GLCanvas3D::_render_collapse_toolbar() const
@ -5428,20 +5437,21 @@ void GLCanvas3D::_render_sla_slices() const
if (!obj->is_step_done(slaposSliceSupports))
continue;
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
SlaCap* sla_caps = const_cast<SlaCap*>(m_sla_caps);
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = sla_caps[0].triangles.find(i);
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = sla_caps[1].triangles.find(i);
{
if (it_caps_bottom == m_sla_caps[0].triangles.end())
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
if (! m_sla_caps[0].matches(clip_min_z)) {
m_sla_caps[0].z = clip_min_z;
if (it_caps_bottom == sla_caps[0].triangles.end())
it_caps_bottom = sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
if (!sla_caps[0].matches(clip_min_z)) {
sla_caps[0].z = clip_min_z;
it_caps_bottom->second.object.clear();
it_caps_bottom->second.supports.clear();
}
if (it_caps_top == m_sla_caps[1].triangles.end())
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
if (! m_sla_caps[1].matches(clip_max_z)) {
m_sla_caps[1].z = clip_max_z;
if (it_caps_top == sla_caps[1].triangles.end())
it_caps_top = sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
if (!sla_caps[1].matches(clip_max_z)) {
sla_caps[1].z = clip_max_z;
it_caps_top->second.object.clear();
it_caps_top->second.supports.clear();
}
@ -5547,7 +5557,7 @@ void GLCanvas3D::_update_volumes_hover_state() const
if (alt_pressed && (shift_pressed || ctrl_pressed)) {
// illegal combinations of keys
m_hover_volume_idxs.clear();
const_cast<std::vector<int>*>(&m_hover_volume_idxs)->clear();
return;
}
@ -5571,7 +5581,7 @@ void GLCanvas3D::_update_volumes_hover_state() const
if (hover_modifiers_only && !hover_from_single_instance) {
// do not allow to select volumes from different instances
m_hover_volume_idxs.clear();
const_cast<std::vector<int>*>(&m_hover_volume_idxs)->clear();
return;
}
@ -5592,23 +5602,15 @@ void GLCanvas3D::_update_volumes_hover_state() const
(deselect && !m_selection.is_single_full_instance() && (volume.object_idx() == m_selection.get_object_idx()) && (volume.instance_idx() == m_selection.get_instance_idx()))
);
if (as_volume) {
if (deselect)
volume.hover = GLVolume::HS_Deselect;
else
volume.hover = GLVolume::HS_Select;
}
if (as_volume)
volume.hover = deselect ? GLVolume::HS_Deselect : GLVolume::HS_Select;
else {
int object_idx = volume.object_idx();
int instance_idx = volume.instance_idx();
for (GLVolume* v : m_volumes.volumes) {
if (v->object_idx() == object_idx && v->instance_idx() == instance_idx) {
if (deselect)
v->hover = GLVolume::HS_Deselect;
else
v->hover = GLVolume::HS_Select;
}
if (v->object_idx() == object_idx && v->instance_idx() == instance_idx)
v->hover = deselect ? GLVolume::HS_Deselect : GLVolume::HS_Select;
}
}
}
@ -6315,31 +6317,47 @@ std::vector<float> GLCanvas3D::_parse_colors(const std::vector<std::string>& col
#if ENABLE_WARNING_TEXTURE_REMOVAL
void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
{
enum ErrorType{
PLATER_WARNING,
PLATER_ERROR,
SLICING_ERROR
};
std::string text;
bool error = false;
ErrorType error = ErrorType::PLATER_WARNING;
switch (warning) {
case EWarning::ObjectOutside: text = _u8L("An object outside the print area was detected."); break;
case EWarning::ToolpathOutside: text = _u8L("A toolpath outside the print area was detected."); error = true; break;
case EWarning::SlaSupportsOutside: text = _u8L("SLA supports outside the print area were detected."); error = true; break;
case EWarning::ToolpathOutside: text = _u8L("A toolpath outside the print area was detected."); error = ErrorType::SLICING_ERROR; break;
case EWarning::SlaSupportsOutside: text = _u8L("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
case EWarning::SomethingNotShown: text = _u8L("Some objects are not visible."); break;
case EWarning::ObjectClashed:
text = _u8L("An object outside the print area was detected.\n"
"Resolve the current problem to continue slicing.");
error = true;
error = ErrorType::PLATER_ERROR;
break;
}
auto& notification_manager = *wxGetApp().plater()->get_notification_manager();
if (state) {
if (error)
notification_manager.push_plater_error_notification(text);
else
switch (error)
{
case PLATER_WARNING:
if (state)
notification_manager.push_plater_warning_notification(text);
}
else {
if (error)
notification_manager.close_plater_error_notification(text);
else
notification_manager.close_plater_warning_notification(text);
break;
case PLATER_ERROR:
if (state)
notification_manager.push_plater_error_notification(text);
else
notification_manager.close_plater_error_notification(text);
break;
case SLICING_ERROR:
if (state)
notification_manager.push_slicing_error_notification(text);
else
notification_manager.close_slicing_error_notification(text);
break;
default:
break;
}
}
#else

View file

@ -449,13 +449,13 @@ private:
wxTimer m_timer;
LayersEditing m_layers_editing;
Mouse m_mouse;
mutable GLGizmosManager m_gizmos;
mutable GLToolbar m_main_toolbar;
mutable GLToolbar m_undoredo_toolbar;
GLGizmosManager m_gizmos;
GLToolbar m_main_toolbar;
GLToolbar m_undoredo_toolbar;
ClippingPlane m_clipping_planes[2];
mutable ClippingPlane m_camera_clipping_plane;
ClippingPlane m_camera_clipping_plane;
bool m_use_clipping_planes;
mutable SlaCap m_sla_caps[2];
SlaCap m_sla_caps[2];
std::string m_sidebar_field;
// when true renders an extra frame by not resetting m_dirty to false
// see request_extra_frame()
@ -463,7 +463,7 @@ private:
int m_extra_frame_requested_delayed { std::numeric_limits<int>::max() };
bool m_event_handlers_bound{ false };
mutable GLVolumeCollection m_volumes;
GLVolumeCollection m_volumes;
GCodeViewer m_gcode_viewer;
RenderTimer m_render_timer;
@ -478,7 +478,6 @@ private:
bool m_dirty;
bool m_initialized;
bool m_apply_zoom_to_volumes_filter;
mutable std::vector<int> m_hover_volume_idxs;
bool m_picking_enabled;
bool m_moving_enabled;
bool m_dynamic_background_enabled;
@ -487,6 +486,7 @@ private:
bool m_tab_down;
ECursorType m_cursor_type;
GLSelectionRectangle m_rectangle_selection;
std::vector<int> m_hover_volume_idxs;
// Following variable is obsolete and it should be safe to remove it.
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
@ -504,13 +504,13 @@ private:
RenderStats m_render_stats;
#endif // ENABLE_RENDER_STATISTICS
mutable int m_imgui_undo_redo_hovered_pos{ -1 };
mutable int m_mouse_wheel {0};
int m_imgui_undo_redo_hovered_pos{ -1 };
int m_mouse_wheel{ 0 };
int m_selected_extruder;
Labels m_labels;
mutable Tooltip m_tooltip;
mutable bool m_tooltip_enabled{ true };
Tooltip m_tooltip;
bool m_tooltip_enabled{ true };
Slope m_slope;
ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla,
@ -519,8 +519,7 @@ private:
PrinterTechnology current_printer_technology() const;
template<class Self>
static auto & get_arrange_settings(Self *self)
{
static auto & get_arrange_settings(Self *self) {
PrinterTechnology ptech = self->current_printer_technology();
auto *ptr = &self->m_arrange_settings_fff;
@ -529,11 +528,10 @@ private:
ptr = &self->m_arrange_settings_sla;
} else if (ptech == ptFFF) {
auto co_opt = self->m_config->template option<ConfigOptionBool>("complete_objects");
if (co_opt && co_opt->value) {
if (co_opt && co_opt->value)
ptr = &self->m_arrange_settings_fff_seq_print;
} else {
else
ptr = &self->m_arrange_settings_fff;
}
}
return *ptr;
@ -715,10 +713,9 @@ public:
double m_rotation = 0.;
BoundingBoxf m_bb;
friend class GLCanvas3D;
public:
inline operator bool() const
{
public:
inline operator bool() const {
return !std::isnan(m_pos.x()) && !std::isnan(m_pos.y());
}
@ -763,8 +760,7 @@ public:
void use_slope(bool use) { m_slope.use(use); }
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
ArrangeSettings get_arrange_settings() const
{
ArrangeSettings get_arrange_settings() const {
const ArrangeSettings &settings = get_arrange_settings(this);
ArrangeSettings ret = settings;
if (&settings == &m_arrange_settings_fff_seq_print) {

View file

@ -428,8 +428,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
bool processed = false;
// mouse anywhere
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
{
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && m_mouse_capture.parent != nullptr) {
if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())) {
// prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
// as when switching between views
@ -441,38 +440,31 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
if (evt.Moving())
update_hover_state(mouse_pos, parent);
else if (evt.LeftUp())
{
if (m_mouse_capture.left)
{
else if (evt.LeftUp()) {
if (m_mouse_capture.left) {
processed = true;
m_mouse_capture.left = false;
}
else
return false;
}
else if (evt.MiddleUp())
{
if (m_mouse_capture.middle)
{
else if (evt.MiddleUp()) {
if (m_mouse_capture.middle) {
processed = true;
m_mouse_capture.middle = false;
}
else
return false;
}
else if (evt.RightUp())
{
if (m_mouse_capture.right)
{
else if (evt.RightUp()) {
if (m_mouse_capture.right) {
processed = true;
m_mouse_capture.right = false;
}
else
return false;
}
else if (evt.Dragging())
{
else if (evt.Dragging()) {
if (m_mouse_capture.any())
// if the button down was done on this toolbar, prevent from dragging into the scene
processed = true;
@ -481,35 +473,29 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
}
int item_id = contains_mouse(mouse_pos, parent);
if (item_id != -1)
{
if (item_id != -1) {
// mouse inside toolbar
if (evt.LeftDown() || evt.LeftDClick())
{
if (evt.LeftDown() || evt.LeftDClick()) {
m_mouse_capture.left = true;
m_mouse_capture.parent = &parent;
processed = true;
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
{
if (item_id != -2 && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
(m_pressed_toggable_id == -1 || m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)) {
// mouse is inside an icon
do_action(GLToolbarItem::Left, item_id, parent, true);
parent.set_as_dirty();
}
}
else if (evt.MiddleDown())
{
else if (evt.MiddleDown()) {
m_mouse_capture.middle = true;
m_mouse_capture.parent = &parent;
}
else if (evt.RightDown())
{
else if (evt.RightDown()) {
m_mouse_capture.right = true;
m_mouse_capture.parent = &parent;
processed = true;
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
{
if (item_id != -2 && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
(m_pressed_toggable_id == -1 || m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)) {
// mouse is inside an icon
do_action(GLToolbarItem::Right, item_id, parent, true);
parent.set_as_dirty();
@ -522,24 +508,26 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
void GLToolbar::calc_layout() const
{
switch (m_layout.type)
Layout* layout = const_cast<Layout*>(&m_layout);
switch (layout->type)
{
default:
case Layout::Horizontal:
{
m_layout.width = get_width_horizontal();
m_layout.height = get_height_horizontal();
layout->width = get_width_horizontal();
layout->height = get_height_horizontal();
break;
}
case Layout::Vertical:
{
m_layout.width = get_width_vertical();
m_layout.height = get_height_vertical();
layout->width = get_width_vertical();
layout->height = get_height_vertical();
break;
}
}
m_layout.dirty = false;
layout->dirty = false;
}
float GLToolbar::get_width_horizontal() const
@ -1196,19 +1184,17 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
left += scaled_border;
top -= scaled_border;
if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0))
if (tex_id == 0 || tex_width <= 0 || tex_height <= 0)
return;
// renders icons
for (const GLToolbarItem* item : m_items)
{
for (const GLToolbarItem* item : m_items) {
if (!item->is_visible())
continue;
if (item->is_separator())
top -= separator_stride;
else
{
else {
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale));
top -= icon_stride;
}
@ -1219,16 +1205,14 @@ bool GLToolbar::generate_icons_texture() const
{
std::string path = resources_dir() + "/icons/";
std::vector<std::string> filenames;
for (GLToolbarItem* item : m_items)
{
for (GLToolbarItem* item : m_items) {
const std::string& icon_filename = item->get_icon_filename();
if (!icon_filename.empty())
filenames.push_back(path + icon_filename);
}
std::vector<std::pair<int, bool>> states;
if (m_type == Normal)
{
if (m_type == Normal) {
states.push_back({ 1, false }); // Normal
states.push_back({ 0, false }); // Pressed
states.push_back({ 2, false }); // Disabled
@ -1236,8 +1220,7 @@ bool GLToolbar::generate_icons_texture() const
states.push_back({ 0, false }); // HoverPressed
states.push_back({ 2, false }); // HoverDisabled
}
else
{
else {
states.push_back({ 1, false }); // Normal
states.push_back({ 1, true }); // Pressed
states.push_back({ 1, false }); // Disabled
@ -1251,9 +1234,9 @@ bool GLToolbar::generate_icons_texture() const
// if (sprite_size_px % 2 != 0)
// sprite_size_px += 1;
bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, sprite_size_px, false);
bool res = const_cast<GLTexture*>(&m_icons_texture)->load_from_svg_files_as_sprites_array(filenames, states, sprite_size_px, false);
if (res)
m_icons_texture_dirty = false;
*const_cast<bool*>(&m_icons_texture_dirty) = false;
return res;
}
@ -1262,8 +1245,7 @@ bool GLToolbar::update_items_visibility()
{
bool ret = false;
for (GLToolbarItem* item : m_items)
{
for (GLToolbarItem* item : m_items) {
ret |= item->update_visibility();
}
@ -1272,12 +1254,10 @@ bool GLToolbar::update_items_visibility()
// updates separators visibility to avoid having two of them consecutive
bool any_item_visible = false;
for (GLToolbarItem* item : m_items)
{
for (GLToolbarItem* item : m_items) {
if (!item->is_separator())
any_item_visible |= item->is_visible();
else
{
else {
item->set_visible(any_item_visible);
any_item_visible = false;
}

View file

@ -233,10 +233,10 @@ private:
EType m_type;
std::string m_name;
bool m_enabled;
mutable GLTexture m_icons_texture;
mutable bool m_icons_texture_dirty;
GLTexture m_icons_texture;
bool m_icons_texture_dirty;
BackgroundTexture m_background_texture;
mutable Layout m_layout;
Layout m_layout;
ItemsList m_items;

View file

@ -244,10 +244,11 @@ private:
// credits infornation
credits = title + " " +
_L("is based on Slic3r by Alessandro Ranellucci and the RepRap community.") + "\n\n" +
_L("is based on Slic3r by Alessandro Ranellucci and the RepRap community.") + "\n" +
_L("Developed by Prusa Research.")+ "\n\n" +
title + " " + _L("is licensed under the") + " " + _L("GNU Affero General Public License, version 3") + "\n\n" +
_L("Contributions by Vojtech Bubnik, Enrico Turri, Oleksandra Iushchenko, Tamas Meszaros, Lukas Matena, Vojtech Kral, David Kocik and numerous others.") + "\n\n" +
_L("Artwork model by Nora Al-Badri and Jan Nikolai Nelles");
_L("Artwork model by M Boyer");
title_font = version_font = credits_font = init_font;
}
@ -691,7 +692,7 @@ void GUI_App::init_app_config()
{
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
// SetAppName(SLIC3R_APP_KEY);
SetAppName(SLIC3R_APP_KEY "-beta");
SetAppName(SLIC3R_APP_KEY "-alpha");
// SetAppDisplayName(SLIC3R_APP_NAME);
// Set the Slic3r data directory at the Slic3r XS module.

View file

@ -858,10 +858,6 @@ void MenuFactory::create_sla_object_menu()
[]() { return plater()->can_split(true); }, m_parent);
m_sla_object_menu.AppendSeparator();
// Add the automatic rotation sub-menu
append_menu_item(&m_sla_object_menu, wxID_ANY, _L("Optimize orientation"), _L("Optimize the rotation of the object for better print results."),
[](wxCommandEvent&) { plater()->optimize_rotation(); });
}
void MenuFactory::create_part_menu()

View file

@ -1531,14 +1531,20 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
if (type == itUndef)
return;
wxDataViewItem parent = m_objects_model->GetParent(item);
if (type & itSettings)
del_settings_from_config(m_objects_model->GetParent(item));
del_settings_from_config(parent);
else if (type & itInstanceRoot && obj_idx != -1)
del_instances_from_object(obj_idx);
else if (type & itLayerRoot && obj_idx != -1)
del_layers_from_object(obj_idx);
else if (type & itLayer && obj_idx != -1)
del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
else if (type & itInfo && obj_idx != -1) {
Unselect(item);
Select(parent);
}
else if (idx == -1)
return;
else if (!del_subobject_from_object(obj_idx, idx, type))
@ -1546,9 +1552,10 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
// If last volume item with warning was deleted, unmark object item
if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
m_objects_model->DeleteWarningIcon(parent);
m_objects_model->Delete(item);
update_info_items(obj_idx);
}
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
@ -2124,20 +2131,32 @@ void ObjectList::part_selection_changed()
{
if (item)
{
if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr)) {
obj_idx = m_objects_model->GetIdByItem(item);
const ItemType type = m_objects_model->GetItemType(item);
const wxDataViewItem parent = m_objects_model->GetParent(item);
const ItemType parent_type = m_objects_model->GetItemType(parent);
obj_idx = m_objects_model->GetObjectIdByItem(item);
if (parent == wxDataViewItem(nullptr)
|| type == itInfo) {
og_name = _(L("Object manipulation"));
m_config = &(*m_objects)[obj_idx]->config;
update_and_show_manipulations = true;
if (type == itInfo) {
InfoItemType info_type = m_objects_model->GetInfoItemType(item);
if (info_type != InfoItemType::VariableLayerHeight) {
GLGizmosManager::EType gizmo_type =
info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports
: GLGizmosManager::EType::Seam;
GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
if (gizmos_mgr.get_current_type() != gizmo_type)
gizmos_mgr.open_gizmo(gizmo_type);
} else
wxGetApp().plater()->toggle_layers_editing(true);
}
}
else {
obj_idx = m_objects_model->GetObjectIdByItem(item);
const ItemType type = m_objects_model->GetItemType(item);
if (type & itSettings) {
const auto parent = m_objects_model->GetParent(item);
const ItemType parent_type = m_objects_model->GetItemType(parent);
if (parent_type & itObject) {
og_name = _(L("Object Settings to modify"));
m_config = &(*m_objects)[obj_idx]->config;
@ -2249,6 +2268,52 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D
return ret;
}
void ObjectList::update_info_items(size_t obj_idx)
{
const ModelObject* model_object = (*m_objects)[obj_idx];
wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx);
assert(item_obj.IsOk());
for (InfoItemType type : {InfoItemType::CustomSupports,
InfoItemType::CustomSeam,
InfoItemType::VariableLayerHeight}) {
wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type);
bool shows = item.IsOk();
bool should_show = false;
switch (type) {
case InfoItemType::CustomSupports :
case InfoItemType::CustomSeam :
should_show = printer_technology() == ptFFF
&& std::any_of(model_object->volumes.begin(), model_object->volumes.end(),
[type](const ModelVolume* mv) {
return ! (type == InfoItemType::CustomSupports
? mv->supported_facets.empty()
: mv->seam_facets.empty());
});
break;
case InfoItemType::VariableLayerHeight :
should_show = printer_technology() == ptFFF
&& ! model_object->layer_height_profile.empty();
break;
}
if (! shows && should_show) {
m_objects_model->AddInfoChild(item_obj, type);
Expand(item_obj);
}
else if (shows && ! should_show) {
Unselect(item);
m_objects_model->Delete(item);
Select(item_obj);
}
}
}
void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
{
auto model_object = (*m_objects)[obj_idx];
@ -2257,6 +2322,8 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
model_object->config.has("extruder") ? model_object->config.extruder() : 0,
get_mesh_errors_count(obj_idx) > 0);
update_info_items(obj_idx);
// add volumes to the object
if (model_object->volumes.size() > 1) {
for (const ModelVolume* volume : model_object->volumes) {
@ -2835,7 +2902,8 @@ void ObjectList::update_selections()
{
const auto item = GetSelection();
if (selection.is_single_full_object()) {
if (m_objects_model->GetItemType(m_objects_model->GetParent(item)) & itObject)
if (m_objects_model->GetItemType(m_objects_model->GetParent(item)) & itObject &&
m_objects_model->GetObjectIdByItem(item) == selection.get_object_idx() )
return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
}
@ -3035,7 +3103,7 @@ void ObjectList::update_selections_on_canvas()
if (sel_cnt == 1) {
wxDataViewItem item = GetSelection();
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer | itInfo))
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode);
else
add_to_selection(item, selection, instance_idx, mode);
@ -3448,6 +3516,9 @@ void ObjectList::update_object_list_by_printer_technology()
m_objects_model->GetChildren(wxDataViewItem(nullptr), object_items);
for (auto& object_item : object_items) {
// update custom supports info
update_info_items(m_objects_model->GetObjectIdByItem(object_item));
// Update Settings Item for object
update_settings_item_and_selection(object_item, sel);

View file

@ -18,7 +18,6 @@
class wxBoxSizer;
class wxBitmapComboBox;
class wxMenuItem;
class ObjectDataViewModel;
class MenuWithSeparators;
namespace Slic3r {
@ -347,6 +346,7 @@ public:
void update_and_show_object_settings_item();
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
void update_object_list_by_printer_technology();
void update_info_items(size_t obj_idx);
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
void instances_to_separated_objects(const int obj_idx);

View file

@ -235,7 +235,7 @@ bool Preview::init(wxWindow* parent, Model* model)
_L("Ironing") + "|1|" +
_L("Bridge infill") + "|1|" +
_L("Gap fill") + "|1|" +
_L("Skirt") + "|1|" +
_L("Skirt/Brim") + "|1|" +
_L("Support material") + "|1|" +
_L("Support material interface") + "|1|" +
_L("Wipe tower") + "|1|" +
@ -250,6 +250,9 @@ bool Preview::init(wxWindow* parent, Model* model)
get_option_type_string(OptionType::Wipe) + "|0|" +
get_option_type_string(OptionType::Retractions) + "|0|" +
get_option_type_string(OptionType::Unretractions) + "|0|" +
#if ENABLE_SEAMS_VISUALIZATION
get_option_type_string(OptionType::Seams) + "|0|" +
#endif // ENABLE_SEAMS_VISUALIZATION
get_option_type_string(OptionType::ToolChanges) + "|0|" +
get_option_type_string(OptionType::ColorChanges) + "|0|" +
get_option_type_string(OptionType::PausePrints) + "|0|" +
@ -1008,6 +1011,9 @@ wxString Preview::get_option_type_string(OptionType type) const
case OptionType::Wipe: { return _L("Wipe"); }
case OptionType::Retractions: { return _L("Retractions"); }
case OptionType::Unretractions: { return _L("Deretractions"); }
#if ENABLE_SEAMS_VISUALIZATION
case OptionType::Seams: { return _L("Seams"); }
#endif // ENABLE_SEAMS_VISUALIZATION
case OptionType::ToolChanges: { return _L("Tool changes"); }
case OptionType::ColorChanges: { return _L("Color changes"); }
case OptionType::PausePrints: { return _L("Print pauses"); }

View file

@ -116,6 +116,9 @@ public:
Wipe,
Retractions,
Unretractions,
#if ENABLE_SEAMS_VISUALIZATION
Seams,
#endif // ENABLE_SEAMS_VISUALIZATION
ToolChanges,
ColorChanges,
PausePrints,

View file

@ -7,6 +7,7 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include <GL/glew.h>
@ -316,8 +317,12 @@ void GLGizmoFdmSupports::update_model_object() const
updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get());
}
if (updated)
if (updated) {
const ModelObjectPtrs& mos = wxGetApp().model().objects;
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
}

View file

@ -7,9 +7,10 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/SLA/Rotfinder.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
namespace Slic3r {
namespace GUI {
@ -204,6 +205,30 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limi
{
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return;
RotoptimzeWindow popup{m_imgui, m_rotoptimizewin_state, {x, y, bottom_limit}};
}
void GLGizmoRotate3D::load_rotoptimize_state()
{
std::string accuracy_str =
wxGetApp().app_config->get("sla_auto_rotate", "accuracy");
std::string method_str =
wxGetApp().app_config->get("sla_auto_rotate", "method_id");
if (!accuracy_str.empty()) {
float accuracy = std::stof(accuracy_str);
accuracy = std::max(0.f, std::min(accuracy, 1.f));
m_rotoptimizewin_state.accuracy = accuracy;
}
if (!method_str.empty()) {
int method_id = std::stoi(method_str);
if (method_id < int(RotoptimizeJob::get_methods_count()))
m_rotoptimizewin_state.method_id = method_id;
}
}
void GLGizmoRotate::render_circle() const
@ -436,6 +461,8 @@ GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_fil
{
m_gizmos[i].set_group_id(i);
}
load_rotoptimize_state();
}
bool GLGizmoRotate3D::on_init()
@ -492,5 +519,51 @@ void GLGizmoRotate3D::on_render() const
m_gizmos[Z].render();
}
const char * GLGizmoRotate3D::RotoptimzeWindow::options[RotoptimizeJob::get_methods_count()];
bool GLGizmoRotate3D::RotoptimzeWindow::options_valid = false;
GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
State & state,
const Alignment &alignment)
: m_imgui{imgui}
{
imgui->begin(_L("Optimize orientation"), ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoCollapse);
// adjust window position to avoid overlap the view toolbar
float win_h = ImGui::GetWindowHeight();
float x = alignment.x, y = alignment.y;
y = std::min(y, alignment.bottom_limit - win_h);
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
ImGui::PushItemWidth(200.f);
size_t methods_cnt = RotoptimizeJob::get_methods_count();
if (!options_valid) {
for (size_t i = 0; i < methods_cnt; ++i)
options[i] = RotoptimizeJob::get_method_names()[i].c_str();
options_valid = true;
}
int citem = state.method_id;
if (ImGui::Combo(_L("Choose goal").c_str(), &citem, options, methods_cnt) ) {
state.method_id = citem;
wxGetApp().app_config->set("sla_auto_rotate", "method_id", std::to_string(state.method_id));
}
ImGui::Separator();
if ( imgui->button(_L("Optimize")) ) {
wxGetApp().plater()->optimize_rotation();
}
}
GLGizmoRotate3D::RotoptimzeWindow::~RotoptimzeWindow()
{
m_imgui->end();
}
} // namespace GUI
} // namespace Slic3r

View file

@ -2,6 +2,7 @@
#define slic3r_GLGizmoRotate_hpp_
#include "GLGizmoBase.hpp"
#include "../Jobs/RotoptimizeJob.hpp"
namespace Slic3r {
@ -136,6 +137,39 @@ protected:
}
void on_render_input_window(float x, float y, float bottom_limit) override;
private:
class RotoptimzeWindow {
ImGuiWrapper *m_imgui = nullptr;
static const char * options [];
static bool options_valid;
public:
struct State {
float accuracy = 1.f;
int method_id = 0;
};
struct Alignment { float x, y, bottom_limit; };
RotoptimzeWindow(ImGuiWrapper * imgui,
State & state,
const Alignment &bottom_limit);
~RotoptimzeWindow();
RotoptimzeWindow(const RotoptimzeWindow&) = delete;
RotoptimzeWindow(RotoptimzeWindow &&) = delete;
RotoptimzeWindow& operator=(const RotoptimzeWindow &) = delete;
RotoptimzeWindow& operator=(RotoptimzeWindow &&) = delete;
};
RotoptimzeWindow::State m_rotoptimizewin_state = {};
void load_rotoptimize_state();
};
} // namespace GUI

View file

@ -7,7 +7,7 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include <GL/glew.h>
@ -222,8 +222,12 @@ void GLGizmoSeam::update_model_object() const
updated |= mv->seam_facets.set(*m_triangle_selectors[idx].get());
}
if (updated)
if (updated) {
const ModelObjectPtrs& mos = wxGetApp().model().objects;
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
}

View file

@ -163,6 +163,17 @@ void GLGizmosManager::reset_all_states()
m_hover = Undefined;
}
bool GLGizmosManager::open_gizmo(EType type)
{
int idx = int(type);
if (m_gizmos[idx]->is_selectable() && m_gizmos[idx]->is_activable()) {
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
update_data();
return true;
}
return false;
}
void GLGizmosManager::set_hover_id(int id)
{
if (!m_enabled || m_current == Undefined)
@ -266,24 +277,21 @@ bool GLGizmosManager::is_running() const
bool GLGizmosManager::handle_shortcut(int key)
{
if (!m_enabled)
if (!m_enabled || m_parent.get_selection().is_empty())
return false;
if (m_parent.get_selection().is_empty())
auto it = std::find_if(m_gizmos.begin(), m_gizmos.end(),
[key](const std::unique_ptr<GLGizmoBase>& gizmo) {
int gizmo_key = gizmo->get_shortcut_key();
return gizmo->is_selectable()
&& ((gizmo_key == key - 64) || (gizmo_key == key - 96));
});
if (it == m_gizmos.end())
return false;
bool handled = false;
for (size_t idx : get_selectable_idxs()) {
int it_key = m_gizmos[idx]->get_shortcut_key();
if (m_gizmos[idx]->is_activable() && ((it_key == key - 64) || (it_key == key - 96))) {
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
handled = true;
}
}
return handled;
EType gizmo_type = EType(it - m_gizmos.begin());
return open_gizmo(gizmo_type);
}
bool GLGizmosManager::is_dragging() const
@ -814,10 +822,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
if (!processed && !evt.HasModifiers())
{
if (handle_shortcut(keyCode))
{
update_data();
processed = true;
}
}
if (processed)
@ -1156,5 +1161,11 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const
return true;
}
int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const
{
return m_gizmos[type]->get_shortcut_key();
}
} // namespace GUI
} // namespace Slic3r

View file

@ -171,6 +171,7 @@ public:
void refresh_on_off_state();
void reset_all_states();
bool is_serializing() const { return m_serializing; }
bool open_gizmo(EType type);
void set_hover_id(int id);
void enable_grabber(EType type, unsigned int id, bool enable);
@ -228,6 +229,7 @@ public:
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); }
int get_shortcut_key(GLGizmosManager::EType) const;
private:
void render_background(float left, float top, float right, float bottom, float border) const;

View file

@ -78,7 +78,7 @@ void ArrangeJob::prepare_all() {
for (ModelObject *obj: m_plater->model().objects)
for (ModelInstance *mi : obj->instances) {
ArrangePolygons & cont = mi->printable ? m_selected : m_unprintable;
cont.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
cont.emplace_back(get_arrange_poly(mi, m_plater));
}
if (auto wti = get_wipe_tower_arrangepoly(*m_plater))
@ -111,7 +111,7 @@ void ArrangeJob::prepare_selected() {
for (size_t i = 0; i < inst_sel.size(); ++i) {
ArrangePolygon &&ap =
get_arrange_poly(PtrWrapper{mo->instances[i]}, m_plater);
get_arrange_poly(mo->instances[i], m_plater);
ArrangePolygons &cont = mo->instances[i]->printable ?
(inst_sel[i] ? m_selected :
@ -161,12 +161,7 @@ void ArrangeJob::process()
{
static const auto arrangestr = _(L("Arranging"));
const GLCanvas3D::ArrangeSettings &settings =
static_cast<const GLCanvas3D*>(m_plater->canvas3D())->get_arrange_settings();
arrangement::ArrangeParams params;
params.allow_rotations = settings.enable_rotation;
params.min_obj_distance = scaled(settings.distance);
arrangement::ArrangeParams params = get_arrange_params(m_plater);
auto count = unsigned(m_selected.size() + m_unprintable.size());
Points bedpts = get_bed_shape(*m_plater->config());
@ -235,4 +230,23 @@ double bed_stride(const Plater *plater) {
return scaled<double>((1. + LOGICAL_BED_GAP) * bedwidth);
}
template<>
arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
const Plater * plater)
{
return get_arrange_poly(PtrWrapper{inst}, plater);
}
arrangement::ArrangeParams get_arrange_params(Plater *p)
{
const GLCanvas3D::ArrangeSettings &settings =
static_cast<const GLCanvas3D*>(p->canvas3D())->get_arrange_settings();
arrangement::ArrangeParams params;
params.allow_rotations = settings.enable_rotation;
params.min_obj_distance = scaled(settings.distance);
return params;
}
}} // namespace Slic3r::GUI

View file

@ -4,7 +4,11 @@
#include "PlaterJob.hpp"
#include "libslic3r/Arrange.hpp"
namespace Slic3r { namespace GUI {
namespace Slic3r {
class ModelInstance;
namespace GUI {
class ArrangeJob : public PlaterJob
{
@ -89,6 +93,11 @@ arrangement::ArrangePolygon get_arrange_poly(T obj, const Plater *plater)
return ap;
}
template<>
arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
const Plater * plater);
arrangement::ArrangeParams get_arrange_params(Plater *p);
}} // namespace Slic3r::GUI

View file

@ -24,7 +24,7 @@ void GUI::Job::run(std::exception_ptr &eptr)
void GUI::Job::update_status(int st, const wxString &msg)
{
auto evt = new wxThreadEvent();
auto evt = new wxThreadEvent(wxEVT_THREAD, m_thread_evt_id);
evt->SetInt(st);
evt->SetString(msg);
wxQueueEvent(this, evt);
@ -33,7 +33,11 @@ void GUI::Job::update_status(int st, const wxString &msg)
GUI::Job::Job(std::shared_ptr<ProgressIndicator> pri)
: m_progress(std::move(pri))
{
Bind(wxEVT_THREAD, [this](const wxThreadEvent &evt) {
m_thread_evt_id = wxNewId();
Bind(wxEVT_THREAD, [this](const wxThreadEvent &evt) {
if (m_finalizing) return;
auto msg = evt.GetString();
if (!msg.empty() && !m_worker_error)
m_progress->set_status_text(msg.ToUTF8().data());
@ -53,13 +57,27 @@ GUI::Job::Job(std::shared_ptr<ProgressIndicator> pri)
m_progress->set_progress(m_range);
on_exception(m_worker_error);
}
else
else {
// This is an RAII solution to remember that finalization is
// running. The run method calls update_status(status_range(), "")
// at the end, which queues up a call to this handler in all cases.
// If process also calls update_status with maxed out status arg
// it will call this handler twice. It is not a problem unless
// yield is called inside the finilize() method, which would
// jump out of finalize and call this handler again.
struct Finalizing {
bool &flag;
Finalizing (bool &f): flag(f) { flag = true; }
~Finalizing() { flag = false; }
} fin(m_finalizing);
finalize();
}
// dont do finalization again for the same process
m_finalized = true;
}
});
}, m_thread_evt_id);
}
void GUI::Job::start()
@ -76,7 +94,8 @@ void GUI::Job::start()
m_progress->set_cancel_callback(
[this]() { m_canceled.store(true); });
m_finalized = false;
m_finalized = false;
m_finalizing = false;
// Changing cursor to busy
wxBeginBusyCursor();

View file

@ -29,9 +29,10 @@ namespace Slic3r { namespace GUI {
class Job : public wxEvtHandler
{
int m_range = 100;
int m_thread_evt_id = wxID_ANY;
boost::thread m_thread;
std::atomic<bool> m_running{false}, m_canceled{false};
bool m_finalized = false;
bool m_finalized = false, m_finalizing = false;
std::shared_ptr<ProgressIndicator> m_progress;
std::exception_ptr m_worker_error = nullptr;

View file

@ -7,47 +7,84 @@
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "libslic3r/AppConfig.hpp"
namespace Slic3r { namespace GUI {
void RotoptimizeJob::prepare()
{
std::string accuracy_str =
wxGetApp().app_config->get("sla_auto_rotate", "accuracy");
std::string method_str =
wxGetApp().app_config->get("sla_auto_rotate", "method_id");
if (!accuracy_str.empty())
m_accuracy = std::stof(accuracy_str);
if (!method_str.empty())
m_method_id = std::stoi(method_str);
m_accuracy = std::max(0.f, std::min(m_accuracy, 1.f));
m_method_id = std::max(size_t(0), std::min(get_methods_count() - 1, m_method_id));
m_default_print_cfg = wxGetApp().preset_bundle->full_config();
const auto &sel = m_plater->get_selection().get_content();
m_selected_object_ids.clear();
m_selected_object_ids.reserve(sel.size());
for (auto &[obj_idx, ignore] : sel)
m_selected_object_ids.emplace_back(obj_idx);
}
void RotoptimizeJob::process()
{
int obj_idx = m_plater->get_selected_object_idx();
if (obj_idx < 0 || int(m_plater->sla_print().objects().size()) <= obj_idx)
return;
ModelObject *o = m_plater->model().objects[size_t(obj_idx)];
const SLAPrintObject *po = m_plater->sla_print().objects()[size_t(obj_idx)];
int prev_status = 0;
auto params =
sla::RotOptimizeParams{}
.accuracy(m_accuracy)
.print_config(&m_default_print_cfg)
.statucb([this, &prev_status](int s)
{
if (s > 0 && s < 100)
update_status(prev_status + s / m_selected_object_ids.size(),
_(L("Searching for optimal orientation")));
if (!o || !po) return;
TriangleMesh mesh = o->raw_mesh();
mesh.require_shared_vertices();
// for (auto inst : o->instances) {
// Transform3d tr = Transform3d::Identity();
// tr.rotate(Eigen::AngleAxisd(inst->get_rotation(Z), Vec3d::UnitZ()));
// tr.rotate(Eigen::AngleAxisd(inst->get_rotation(Y), Vec3d::UnitY()));
// tr.rotate(Eigen::AngleAxisd(inst->get_rotation(X), Vec3d::UnitX()));
// double score = sla::get_model_supportedness(*po, tr);
// std::cout << "Model supportedness before: " << score << std::endl;
// }
Vec2d r = sla::find_best_rotation(*po, 0.75f,
[this](unsigned s) {
if (s < 100)
update_status(int(s), _(L("Searching for optimal orientation")));
},
[this] () { return was_canceled(); });
return !was_canceled();
});
double mindist = 6.0; // FIXME
for (ObjRot &objrot : m_selected_object_ids) {
ModelObject *o = m_plater->model().objects[size_t(objrot.idx)];
if (!o) continue;
if (Methods[m_method_id].findfn)
objrot.rot = Methods[m_method_id].findfn(*o, params);
prev_status += 100 / m_selected_object_ids.size();
if (was_canceled()) break;
}
update_status(100, was_canceled() ? _(L("Orientation search canceled.")) :
_(L("Orientation found.")));
}
void RotoptimizeJob::finalize()
{
if (was_canceled()) return;
for (const ObjRot &objrot : m_selected_object_ids) {
ModelObject *o = m_plater->model().objects[size_t(objrot.idx)];
if (!o) continue;
if (!was_canceled()) {
for(ModelInstance * oi : o->instances) {
oi->set_rotation({r[X], r[Y], 0.});
if (objrot.rot)
oi->set_rotation({objrot.rot->x(), objrot.rot->y(), 0.});
auto trmatrix = oi->get_transformation().get_matrix();
Polygon trchull = o->convex_hull_2d(trmatrix);
@ -63,19 +100,13 @@ void RotoptimizeJob::process()
oi->set_rotation(rt);
}
m_plater->find_new_position(o->instances, scaled(mindist));
// Correct the z offset of the object which was corrupted be
// the rotation
o->ensure_on_bed();
// m_plater->find_new_position(o->instances);
}
update_status(100, was_canceled() ? _(L("Orientation search canceled.")) :
_(L("Orientation found.")));
}
void RotoptimizeJob::finalize()
{
if (!was_canceled())
m_plater->update();

View file

@ -3,17 +3,70 @@
#include "PlaterJob.hpp"
namespace Slic3r { namespace GUI {
#include "libslic3r/SLA/Rotfinder.hpp"
#include "libslic3r/PrintConfig.hpp"
namespace Slic3r {
namespace GUI {
class RotoptimizeJob : public PlaterJob
{
using FindFn = std::function<Vec2d(const ModelObject & mo,
const sla::RotOptimizeParams &params)>;
struct FindMethod { std::string name; FindFn findfn; };
static inline const FindMethod Methods[] = {
{ L("Best surface quality"), sla::find_best_misalignment_rotation },
{ L("Least supports"), sla::find_least_supports_rotation },
// Just a min area bounding box that is done for all methods anyway.
{ L("Z axis only"), nullptr }
};
size_t m_method_id = 0;
float m_accuracy = 0.75;
DynamicPrintConfig m_default_print_cfg;
struct ObjRot
{
size_t idx;
std::optional<Vec2d> rot;
ObjRot(size_t id): idx{id}, rot{} {}
};
std::vector<ObjRot> m_selected_object_ids;
protected:
void prepare() override;
public:
RotoptimizeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater)
: PlaterJob{std::move(pri), plater}
{}
void process() override;
void finalize() override;
static constexpr size_t get_methods_count() { return std::size(Methods); }
static const auto & get_method_names()
{
static bool m_method_names_valid = false;
static std::array<std::string, std::size(Methods)> m_method_names;
if (!m_method_names_valid) {
for (size_t i = 0; i < std::size(Methods); ++i)
m_method_names[i] = _utf8(Methods[i].name);
m_method_names_valid = true;
}
return m_method_names;
}
};
}} // namespace Slic3r::GUI

View file

@ -132,7 +132,8 @@ SLAImportJob::~SLAImportJob() = default;
void SLAImportJob::process()
{
auto progr = [this](int s) {
if (s < 100) update_status(int(s), _(L("Importing SLA archive")));
if (s < 100)
update_status(int(s), _(L("Importing SLA archive")));
return !was_canceled();
};
@ -178,7 +179,7 @@ void SLAImportJob::prepare()
if (dlg.ShowModal() == wxID_OK) {
auto path = dlg.get_path();
auto nm = wxFileName(path);
p->path = !nm.Exists(wxFILE_EXISTS_REGULAR) ? "" : path.ToUTF8();
p->path = !nm.Exists(wxFILE_EXISTS_REGULAR) ? "" : nm.GetFullPath();
p->sel = dlg.get_selection();
p->win = dlg.get_marchsq_windowsize();
} else {

View file

@ -534,6 +534,10 @@ void MainFrame::init_tabpanel()
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
#endif
#if wxCHECK_VERSION(3,1,3)
if (wxSystemSettings::GetAppearance().IsDark())
m_tabpanel->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
m_tabpanel->Hide();
m_settings_dialog.set_tabpanel(m_tabpanel);
@ -877,6 +881,9 @@ void MainFrame::on_sys_color_changed()
// update label colors in respect to the system mode
wxGetApp().init_label_colours();
#ifdef __WXMSW__
m_tabpanel->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
// update Plater
wxGetApp().plater()->sys_color_changed();
@ -1526,10 +1533,10 @@ void MainFrame::repair_stl()
output_file = dlg.GetPath();
}
auto tmesh = new Slic3r::TriangleMesh();
tmesh->ReadSTLFile(input_file.ToUTF8().data());
tmesh->repair();
tmesh->WriteOBJFile(output_file.ToUTF8().data());
Slic3r::TriangleMesh tmesh;
tmesh.ReadSTLFile(input_file.ToUTF8().data());
tmesh.repair();
tmesh.WriteOBJFile(output_file.ToUTF8().data());
Slic3r::GUI::show_info(this, L("Your file was repaired."), L("Repair"));
}

View file

@ -169,13 +169,16 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f);
imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
// find if hovered
if (m_state == EState::Hovered)
m_state = EState::Shown;
// find if hovered FIXME: do it only in update state?
if (m_state == EState::Hovered) {
m_state = EState::Unknown;
init();
}
if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y && mouse_pos.y < win_pos.y + m_window_height) {
ImGui::SetNextWindowFocus();
m_state = EState::Hovered;
set_hovered();
}
// color change based on fading out
@ -185,22 +188,8 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
fading_pop = true;
}
// background color
if (m_is_gray) {
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
}
else if (m_data.level == NotificationLevel::ErrorNotification) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
}
else if (m_data.level == NotificationLevel::WarningNotification) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
backcolor.y += 0.15f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
}
bool bgrnd_color_pop = push_background_color();
// name of window indentifies window - has to be unique string
if (m_id == 0)
@ -219,13 +208,34 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
}
imgui.end();
if (m_is_gray || m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification)
if (bgrnd_color_pop)
ImGui::PopStyleColor();
if (fading_pop)
ImGui::PopStyleColor(2);
}
bool NotificationManager::PopNotification::push_background_color()
{
if (m_is_gray) {
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
return true;
}
if (m_data.level == NotificationLevel::ErrorNotification) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
return true;
}
if (m_data.level == NotificationLevel::WarningNotification) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
backcolor.y += 0.15f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
return true;
}
return false;
}
void NotificationManager::PopNotification::count_spaces()
{
//determine line width
@ -242,34 +252,28 @@ void NotificationManager::PopNotification::count_spaces()
m_window_width = m_line_height * 25;
}
void NotificationManager::PopNotification::init()
void NotificationManager::PopNotification::count_lines()
{
// Do not init closing notification
if (is_finished())
return;
std::string text = m_text1 + " " + m_hypertext;
size_t last_end = 0;
m_lines_count = 0;
std::string text = m_text1 + " " + m_hypertext;
size_t last_end = 0;
m_lines_count = 0;
count_spaces();
// count lines
m_endlines.clear();
while (last_end < text.length() - 1)
{
size_t next_hard_end = text.find_first_of('\n', last_end);
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
size_t next_hard_end = text.find_first_of('\n', last_end);
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
//next line is ended by '/n'
m_endlines.push_back(next_hard_end);
last_end = next_hard_end + 1;
} else {
}
else {
// find next suitable endline
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
// more than one line till end
size_t next_space = text.find_first_of(' ', last_end);
size_t next_space = text.find_first_of(' ', last_end);
if (next_space > 0) {
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) {
next_space = next_space_candidate;
next_space_candidate = text.find_first_of(' ', next_space + 1);
@ -283,7 +287,8 @@ void NotificationManager::PopNotification::init()
}
m_endlines.push_back(last_end + letter_count);
last_end += letter_count;
} else {
}
else {
m_endlines.push_back(next_space);
last_end = next_space + 1;
}
@ -297,11 +302,22 @@ void NotificationManager::PopNotification::init()
}
m_lines_count++;
}
}
void NotificationManager::PopNotification::init()
{
// Do not init closing notification
if (is_finished())
return;
count_spaces();
count_lines();
if (m_lines_count == 3)
m_multiline = true;
m_notification_start = GLCanvas3D::timestamp_now();
//if (m_state != EState::Hidden)
// m_state = EState::Shown;
if (m_state == EState::Unknown)
m_state = EState::Shown;
}
void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui)
{
@ -324,8 +340,8 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
if (m_multiline) {
int last_end = 0;
float starting_y = m_line_height/2;//10;
float shift_y = m_line_height;// -m_line_height / 20;
float starting_y = m_line_height/2;
float shift_y = m_line_height;
for (size_t i = 0; i < m_lines_count; i++) {
std::string line = m_text1.substr(last_end , m_endlines[i] - last_end);
if(i < m_lines_count - 1)
@ -549,7 +565,7 @@ void NotificationManager::PopNotification::update(const NotificationData& n)
m_text2 = n.text2;
init();
}
bool NotificationManager::PopNotification::compare_text(const std::string& text)
bool NotificationManager::PopNotification::compare_text(const std::string& text) const
{
std::wstring wt1 = boost::nowide::widen(m_text1);
std::wstring wt2 = boost::nowide::widen(text);
@ -579,9 +595,10 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64
// reset timers - hovered state is set in render
if (m_state == EState::Hovered) {
m_current_fade_opacity = 1.0f;
m_notification_start = now;
m_state = EState::Unknown;
init();
// Timers when not fading
} else if (m_state != EState::FadingOut && m_data.duration != 0 && !paused) {
} else if (m_state != EState::NotFading && m_state != EState::FadingOut && m_data.duration != 0 && !paused) {
int64_t up_time = now - m_notification_start;
if (up_time >= m_data.duration * 1000) {
m_state = EState::FadingOut;
@ -785,53 +802,154 @@ bool NotificationManager::ExportFinishedNotification::on_text_click()
void NotificationManager::ProgressBarNotification::init()
{
PopNotification::init();
m_lines_count++;
m_endlines.push_back(m_endlines.back());
}
void NotificationManager::ProgressBarNotification::count_spaces()
{
//determine line width
m_line_height = ImGui::CalcTextSize("A").y;
m_left_indentation = m_line_height;
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
std::string text;
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
m_left_indentation = picture_width + m_line_height / 2;
//m_lines_count++;
if(m_lines_count >= 2) {
m_lines_count = 3;
m_multiline = true;
while (m_endlines.size() < 3)
m_endlines.push_back(m_endlines.back());
} else {
m_lines_count = 2;
m_endlines.push_back(m_endlines.back());
}
m_window_width_offset = m_line_height * (m_has_cancel_button ? 6 : 4);
m_window_width = m_line_height * 25;
if(m_state == EState::Shown)
m_state = EState::NotFading;
}
void NotificationManager::ProgressBarNotification::count_lines()
{
std::string text = m_text1 + " " + m_hypertext;
size_t last_end = 0;
m_lines_count = 0;
m_endlines.clear();
while (last_end < text.length() - 1)
{
size_t next_hard_end = text.find_first_of('\n', last_end);
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
//next line is ended by '/n'
m_endlines.push_back(next_hard_end);
last_end = next_hard_end + 1;
}
else {
// find next suitable endline
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
// more than one line till end
size_t next_space = text.find_first_of(' ', last_end);
if (next_space > 0) {
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) {
next_space = next_space_candidate;
next_space_candidate = text.find_first_of(' ', next_space + 1);
}
// when one word longer than line. Or the last space is too early.
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset ||
ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 4 * 3
) {
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) {
letter_count++;
}
m_endlines.push_back(last_end + letter_count);
last_end += letter_count;
}
else {
m_endlines.push_back(next_space);
last_end = next_space + 1;
}
}
}
else {
m_endlines.push_back(text.length());
last_end = text.length();
}
}
m_lines_count++;
}
}
void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
// line1 - we do not print any more text than what fits on line 1. Line 2 is bar.
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(win_size_y / 2 - win_size_y / 6 - m_line_height / 2);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
if (m_has_cancel_button)
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
if (m_multiline) {
// two lines text, one line bar
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height / 4);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height + m_line_height / 4);
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
imgui.text(line.c_str());
if (m_has_cancel_button)
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
} else {
//one line text, one line bar
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(/*win_size_y / 2 - win_size_y / 6 -*/ m_line_height / 4);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
if (m_has_cancel_button)
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
}
void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f);
ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 4);
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + m_line_height / 4);
ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + (m_multiline ? m_line_height / 2 : 0));
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + (m_multiline ? m_line_height / 2 : 0));
ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y);
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f);
ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f);
}
//------PrintHostUploadNotification----------------
void NotificationManager::PrintHostUploadNotification::init()
{
ProgressBarNotification::init();
if (m_state == EState::NotFading && m_uj_state == UploadJobState::PB_COMPLETED)
m_state = EState::Shown;
}
void NotificationManager::PrintHostUploadNotification::count_spaces()
{
//determine line width
m_line_height = ImGui::CalcTextSize("A").y;
m_left_indentation = m_line_height;
if (m_uj_state == UploadJobState::PB_ERROR) {
std::string text;
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
m_left_indentation = picture_width + m_line_height / 2;
}
m_window_width_offset = m_line_height * 6; //(m_has_cancel_button ? 6 : 4);
m_window_width = m_line_height * 25;
}
bool NotificationManager::PrintHostUploadNotification::push_background_color()
{
if (m_uj_state == UploadJobState::PB_ERROR) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
return true;
}
return false;
}
void NotificationManager::PrintHostUploadNotification::set_percentage(float percent)
{
m_percentage = percent;
if (percent >= 1.0f) {
m_uj_state = UploadJobState::PB_COMPLETED;
m_has_cancel_button = false;
init();
} else if (percent < 0.0f) {
error();
} else {
@ -846,34 +964,44 @@ void NotificationManager::PrintHostUploadNotification::render_bar(ImGuiWrapper&
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_PROGRESS:
{
ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
float uploaded = m_file_size / 100 * m_percentage;
float uploaded = m_file_size * m_percentage;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "% - " << uploaded << " of " << m_file_size << "MB uploaded";
text = stream.str();
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 /*- m_line_height / 4 * 3*/);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? 0 : m_line_height / 4));
break;
}
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_ERROR:
text = _u8L("ERROR");
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? m_line_height / 4 : m_line_height / 2));
break;
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_CANCELLED:
text = _u8L("CANCELED");
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? m_line_height / 4 : m_line_height / 2));
break;
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_COMPLETED:
text = _u8L("COMPLETED");
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? m_line_height / 4 : m_line_height / 2));
break;
}
imgui.text(text.c_str());
}
void NotificationManager::PrintHostUploadNotification::render_left_sign(ImGuiWrapper& imgui)
{
if (m_uj_state == UploadJobState::PB_ERROR) {
std::string text;
text = ImGui::ErrorMarker;
ImGui::SetCursorPosX(m_line_height / 3);
ImGui::SetCursorPosY(m_window_height / 2 - m_line_height);
imgui.text(text.c_str());
}
}
void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
@ -1059,6 +1187,14 @@ void NotificationManager::close_slicing_errors_and_warnings()
}
}
}
void NotificationManager::close_slicing_error_notification(const std::string& text)
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::SlicingError && notification->compare_text(_u8L("ERROR:") + "\n" + text)) {
notification->close();
}
}
}
void NotificationManager::push_slicing_complete_notification(int timestamp, bool large)
{
std::string hypertext;
@ -1122,39 +1258,53 @@ void NotificationManager::push_exporting_finished_notification(const std::string
void NotificationManager::push_upload_job_notification(int id, float filesize, const std::string& filename, const std::string& host, float percentage)
{
// find if upload with same id was not already in notification
// done by compare_jon_id not compare_text thus has to be performed here
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::PrintHostUpload && dynamic_cast<PrintHostUploadNotification*>(notification.get())->compare_job_id(id)) {
return;
}
}
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 0, text };
NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 10, text };
push_notification_data(std::make_unique<NotificationManager::PrintHostUploadNotification>(data, m_id_provider, m_evt_handler, 0, id, filesize), 0);
}
void NotificationManager::set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage)
{
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
dynamic_cast<PrintHostUploadNotification*>(notification.get())->set_percentage(percentage);
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
if (notification->get_type() == NotificationType::PrintHostUpload) {
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
if (phun->compare_job_id(id)) {
phun->set_percentage(percentage);
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
break;
}
}
}
}
void NotificationManager::upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host)
{
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
dynamic_cast<PrintHostUploadNotification*>(notification.get())->cancel();
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
break;
if (notification->get_type() == NotificationType::PrintHostUpload) {
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
if (phun->compare_job_id(id)) {
phun->cancel();
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
break;
}
}
}
}
void NotificationManager::upload_job_notification_show_error(int id, const std::string& filename, const std::string& host)
{
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
dynamic_cast<PrintHostUploadNotification*>(notification.get())->error();
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
break;
if (notification->get_type() == NotificationType::PrintHostUpload) {
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
if(phun->compare_job_id(id)) {
phun->error();
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
break;
}
}
}
}

View file

@ -125,6 +125,7 @@ public:
// void set_slicing_warning_gray(const std::string& text, bool g);
// immediately stops showing slicing errors
void close_slicing_errors_and_warnings();
void close_slicing_error_notification(const std::string& text);
// Release those slicing warnings, which refer to an ObjectID, which is not in the list.
// living_oids is expected to be sorted.
void remove_slicing_warnings_of_released_objects(const std::vector<ObjectID>& living_oids);
@ -207,6 +208,7 @@ private:
Unknown, // NOT initialized
Hidden,
Shown, // Requesting Render at some time if duration != 0
NotFading, // Never jumps to state Fading out even if duration says so
FadingOut, // Requesting Render at some time
ClosePending, // Requesting Render
Finished, // Requesting Render
@ -230,18 +232,17 @@ private:
const NotificationData get_data() const { return m_data; }
const bool is_gray() const { return m_is_gray; }
void set_gray(bool g) { m_is_gray = g; }
bool compare_text(const std::string& text);
virtual bool compare_text(const std::string& text) const;
void hide(bool h) { if (is_finished()) return; m_state = h ? EState::Hidden : EState::Unknown; }
// sets m_next_render with time of next mandatory rendering. Delta is time since last render.
bool update_state(bool paused, const int64_t delta);
int64_t next_render() const { return is_finished() ? 0 : m_next_render; }
EState get_state() const { return m_state; }
bool is_hovered() const { return m_state == EState::Hovered; }
void set_hovered() { if (m_state != EState::Finished && m_state != EState::ClosePending && m_state != EState::Hidden && m_state != EState::Unknown) m_state = EState::Hovered; }
protected:
// Call after every size change
virtual void init();
// Part of init()
virtual void count_spaces();
// Calculetes correct size but not se it in imgui!
virtual void set_next_window_size(ImGuiWrapper& imgui);
virtual void render_text(ImGuiWrapper& imgui,
@ -255,13 +256,20 @@ private:
const std::string text,
bool more = false);
// Left sign could be error or warning sign
void render_left_sign(ImGuiWrapper& imgui);
virtual void render_left_sign(ImGuiWrapper& imgui);
virtual void render_minimize_button(ImGuiWrapper& imgui,
const float win_pos_x, const float win_pos_y);
// Hypertext action, returns true if notification should close.
// Action is stored in NotificationData::callback as std::function<bool(wxEvtHandler*)>
virtual bool on_text_click();
protected:
// Part of init(), counts horizontal spacing like left indentation
virtual void count_spaces();
// Part of init(), counts end lines
virtual void count_lines();
// returns true if PopStyleColor should be called later to pop this push
virtual bool push_background_color();
const NotificationData m_data;
// For reusing ImGUI windows.
NotificationIDProvider &m_id_provider;
@ -364,7 +372,8 @@ private:
virtual void set_percentage(float percent) { m_percentage = percent; }
protected:
virtual void init() override;
virtual void count_spaces() override;
virtual void count_lines() override;
virtual void render_text(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
@ -375,6 +384,8 @@ private:
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y)
{}
virtual void render_minimize_button(ImGuiWrapper& imgui,
const float win_pos_x, const float win_pos_y) override {}
float m_percentage;
bool m_has_cancel_button {false};
@ -401,17 +412,23 @@ private:
{
m_has_cancel_button = true;
}
static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return "[" + std::to_string(id) + "] " + filename + " -> " + host; }
static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return /*"[" + std::to_string(id) + "] " + */filename + " -> " + host; }
virtual void set_percentage(float percent) override;
void cancel() { m_uj_state = UploadJobState::PB_CANCELLED; m_has_cancel_button = false; }
void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; }
void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; init(); }
bool compare_job_id(const int other_id) const { return m_job_id == other_id; }
virtual bool compare_text(const std::string& text) const override { return false; }
protected:
virtual void init() override;
virtual void count_spaces() override;
virtual bool push_background_color() override;
virtual void render_bar(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
virtual void render_cancel_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
virtual void render_left_sign(ImGuiWrapper& imgui) override;
// Identifies job in cancel callback
int m_job_id;
// Size of uploaded size to be displayed in MB

View file

@ -47,6 +47,19 @@ void ObjectDataViewModelNode::init_container()
static constexpr char LayerRootIcon[] = "edit_layers_all";
static constexpr char LayerIcon[] = "edit_layers_some";
static constexpr char WarningIcon[] = "exclamation";
static constexpr char InfoIcon[] = "info";
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType info_type) :
m_parent(parent),
m_type(itInfo),
m_extruder(wxEmptyString)
{
m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports")
: info_type == InfoItemType::CustomSeam ? _L("Paint-on seam")
: _L("Variable layer height");
m_info_item_type = info_type;
}
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
m_parent(parent),
@ -69,6 +82,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
m_bmp = create_scaled_bitmap(LayerRootIcon); // FIXME: pass window ptr
m_name = _(L("Layers"));
}
else if (type == itInfo)
assert(false);
if (type & (itInstanceRoot | itLayerRoot))
init_container();
@ -250,6 +265,7 @@ ObjectDataViewModel::ObjectDataViewModel()
m_volume_bmps = MenuFactory::get_volume_bitmaps();
m_warning_bmp = create_scaled_bitmap(WarningIcon);
m_info_bmp = create_scaled_bitmap(InfoIcon);
}
ObjectDataViewModel::~ObjectDataViewModel()
@ -330,12 +346,37 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
return child;
}
wxDataViewItem ObjectDataViewModel::AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type)
{
ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
if (!root) return wxDataViewItem(0);
const auto node = new ObjectDataViewModelNode(root, info_type);
// The new item should be added according to its order in InfoItemType.
// Find last info item with lower index and append after it.
const auto& children = root->GetChildren();
int idx = -1;
for (int i=0; i<int(children.size()); ++i) {
if (children[i]->GetType() == itInfo && int(children[i]->GetInfoItemType()) < int(info_type) )
idx = i;
}
root->Insert(node, idx+1);
node->SetBitmap(m_info_bmp);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
return child;
}
wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &parent_item)
{
ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
if (!root) return wxDataViewItem(0);
const auto node = new ObjectDataViewModelNode(root, itSettings);
root->Insert(node, 0);
// notify control
const wxDataViewItem child((void*)node);
@ -1379,6 +1420,14 @@ ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
return node->m_type < 0 ? itUndef : node->m_type;
}
InfoItemType ObjectDataViewModel::GetInfoItemType(const wxDataViewItem &item) const
{
if (!item.IsOk())
return InfoItemType::Undef;
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
return node->m_info_item_type;
}
wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const
{
if (!parent_item.IsOk())
@ -1411,6 +1460,21 @@ wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item)
return GetItemByType(item, itLayerRoot);
}
wxDataViewItem ObjectDataViewModel::GetInfoItemByType(const wxDataViewItem &parent_item, InfoItemType type) const
{
if (! parent_item.IsOk())
return wxDataViewItem(0);
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
for (size_t i = 0; i < node->GetChildCount(); i++) {
const ObjectDataViewModelNode* child_node = node->GetNthChild(i);
if (child_node->m_type == itInfo && child_node->m_info_item_type == type)
return wxDataViewItem((void*)child_node);
}
return wxDataViewItem(0); // not found
}
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
{
if (!item.IsOk())

View file

@ -27,6 +27,7 @@ enum ItemType {
itSettings = 16,
itLayerRoot = 32,
itLayer = 64,
itInfo = 128
};
enum ColumnNumber
@ -44,6 +45,14 @@ enum PrintIndicator
piUnprintable , // unprintable
};
enum class InfoItemType
{
Undef,
CustomSupports,
CustomSeam,
VariableLayerHeight
};
class ObjectDataViewModelNode;
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
@ -69,6 +78,7 @@ class ObjectDataViewModelNode
std::string m_action_icon_name = "";
ModelVolumeType m_volume_type;
InfoItemType m_info_item_type {InfoItemType::Undef};
public:
ObjectDataViewModelNode(const wxString& name,
@ -104,6 +114,7 @@ public:
const wxString& extruder = wxEmptyString );
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType type);
~ObjectDataViewModelNode()
{
@ -176,6 +187,7 @@ public:
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
InfoItemType GetInfoItemType() const { return m_info_item_type; }
void SetIdx(const int& idx);
int GetIdx() const { return m_idx; }
ModelVolumeType GetVolumeType() { return m_volume_type; }
@ -244,6 +256,7 @@ class ObjectDataViewModel :public wxDataViewModel
std::vector<ObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap> m_volume_bmps;
wxBitmap m_warning_bmp;
wxBitmap m_info_bmp;
wxDataViewCtrl* m_ctrl { nullptr };
@ -261,6 +274,7 @@ public:
const int extruder = 0,
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
@ -335,12 +349,15 @@ public:
// In our case it is an item with all columns
bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
ItemType GetItemType(const wxDataViewItem &item) const ;
ItemType GetItemType(const wxDataViewItem &item) const;
InfoItemType GetInfoItemType(const wxDataViewItem &item) const;
wxDataViewItem GetItemByType( const wxDataViewItem &parent_item,
ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
wxDataViewItem GetInfoItemByType(const wxDataViewItem &parent_item, InfoItemType type) const;
bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest( const wxDataViewItem &item,
const std::vector<std::string>& categories);

View file

@ -90,22 +90,24 @@ float OpenGLManager::GLInfo::get_max_anisotropy() const
void OpenGLManager::GLInfo::detect() const
{
m_version = gl_get_string_safe(GL_VERSION, "N/A");
m_glsl_version = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION, "N/A");
m_vendor = gl_get_string_safe(GL_VENDOR, "N/A");
m_renderer = gl_get_string_safe(GL_RENDERER, "N/A");
*const_cast<std::string*>(&m_version) = gl_get_string_safe(GL_VERSION, "N/A");
*const_cast<std::string*>(&m_glsl_version) = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION, "N/A");
*const_cast<std::string*>(&m_vendor) = gl_get_string_safe(GL_VENDOR, "N/A");
*const_cast<std::string*>(&m_renderer) = gl_get_string_safe(GL_RENDERER, "N/A");
glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_max_tex_size));
int* max_tex_size = const_cast<int*>(&m_max_tex_size);
glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, max_tex_size));
m_max_tex_size /= 2;
*max_tex_size /= 2;
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
m_max_tex_size /= 2;
*max_tex_size /= 2;
if (GLEW_EXT_texture_filter_anisotropic)
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy));
m_detected = true;
if (GLEW_EXT_texture_filter_anisotropic) {
float* max_anisotropy = const_cast<float*>(&m_max_anisotropy);
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
}
*const_cast<bool*>(&m_detected) = true;
}
static bool version_greater_or_equal_to(const std::string& version, unsigned int major, unsigned int minor)
@ -174,19 +176,16 @@ std::string OpenGLManager::GLInfo::to_string(bool format_as_html, bool extension
out << b_start << "Renderer: " << b_end << m_renderer << line_end;
out << b_start << "GLSL version: " << b_end << m_glsl_version << line_end;
if (extensions)
{
if (extensions) {
std::vector<std::string> extensions_list;
std::string extensions_str = gl_get_string_safe(GL_EXTENSIONS, "");
boost::split(extensions_list, extensions_str, boost::is_any_of(" "), boost::token_compress_off);
if (!extensions_list.empty())
{
if (!extensions_list.empty()) {
out << h2_start << "Installed extensions:" << h2_end << line_end;
std::sort(extensions_list.begin(), extensions_list.end());
for (const std::string& ext : extensions_list)
{
for (const std::string& ext : extensions_list) {
out << ext << line_end;
}
}
@ -252,7 +251,7 @@ bool OpenGLManager::init_gl()
message += _L("You may need to update your graphics card driver.");
#ifdef _WIN32
message += "\n";
message += _L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter.");
message += _L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw-renderer parameter.");
#endif
wxMessageBox(message, wxString("PrusaSlicer - ") + _L("Unsupported OpenGL version"), wxOK | wxICON_ERROR);
}
@ -304,8 +303,7 @@ wxGLCanvas* OpenGLManager::create_wxglcanvas(wxWindow& parent)
0
};
if (s_multisample == EMultisampleState::Unknown)
{
if (s_multisample == EMultisampleState::Unknown) {
detect_multisample(attribList);
// // debug output
// std::cout << "Multisample " << (can_multisample() ? "enabled" : "disabled") << std::endl;

View file

@ -22,14 +22,14 @@ public:
class GLInfo
{
mutable bool m_detected{ false };
mutable int m_max_tex_size{ 0 };
mutable float m_max_anisotropy{ 0.0f };
bool m_detected{ false };
int m_max_tex_size{ 0 };
float m_max_anisotropy{ 0.0f };
mutable std::string m_version;
mutable std::string m_glsl_version;
mutable std::string m_vendor;
mutable std::string m_renderer;
std::string m_version;
std::string m_glsl_version;
std::string m_vendor;
std::string m_renderer;
public:
GLInfo() = default;

View file

@ -967,6 +967,10 @@ void Sidebar::msw_rescale()
void Sidebar::sys_color_changed()
{
#ifdef __WXMSW__
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
for (PlaterPresetComboBox* combo : std::vector<PlaterPresetComboBox*>{ p->combo_print,
p->combo_sla_print,
p->combo_sla_material,
@ -975,6 +979,7 @@ void Sidebar::sys_color_changed()
for (PlaterPresetComboBox* combo : p->combos_filament)
combo->msw_rescale();
p->object_list->msw_rescale();
p->object_list->sys_color_changed();
p->object_manipulation->sys_color_changed();
p->object_layers->sys_color_changed();
@ -2439,6 +2444,29 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
#endif /* AUTOPLACEMENT_ON_LOAD */
}
#if ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
const Vec3d size = object->instance_bounding_box(i).size();
const Vec3d ratio = size.cwiseQuotient(bed_size);
const double max_ratio = std::max(ratio(0), ratio(1));
if (max_ratio > 10000) {
// the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
// so scale down the mesh
double inv = 1. / max_ratio;
object->scale_mesh_after_creation(inv * Vec3d::Ones());
object->origin_translation = Vec3d::Zero();
object->center_around_origin();
scaled_down = true;
break;
}
else if (max_ratio > 5) {
const Vec3d inverse = 1.0 / max_ratio * Vec3d::Ones();
instance->set_scaling_factor(inverse.cwiseProduct(instance->get_scaling_factor()));
scaled_down = true;
}
}
#else
const Vec3d size = object->bounding_box().size();
const Vec3d ratio = size.cwiseQuotient(bed_size);
const double max_ratio = std::max(ratio(0), ratio(1));
@ -2457,6 +2485,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
}
scaled_down = true;
}
#endif // ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG
object->ensure_on_bed();
}
@ -2701,32 +2730,36 @@ void Plater::priv::mirror(Axis axis)
view3D->mirror_selection(axis);
}
void Plater::find_new_position(const ModelInstancePtrs &instances,
coord_t min_d)
void Plater::find_new_position(const ModelInstancePtrs &instances)
{
arrangement::ArrangePolygons movable, fixed;
arrangement::ArrangeParams arr_params = get_arrange_params(this);
for (const ModelObject *mo : p->model.objects)
for (const ModelInstance *inst : mo->instances) {
for (ModelInstance *inst : mo->instances) {
auto it = std::find(instances.begin(), instances.end(), inst);
auto arrpoly = inst->get_arrange_polygon();
auto arrpoly = get_arrange_poly(inst, this);
if (it == instances.end())
fixed.emplace_back(std::move(arrpoly));
else
else {
arrpoly.setter = [it](const arrangement::ArrangePolygon &p) {
if (p.is_arranged() && p.bed_idx == 0) {
Vec2d t = p.translation.cast<double>();
(*it)->apply_arrange_result(t, p.rotation);
}
};
movable.emplace_back(std::move(arrpoly));
}
}
if (auto wt = get_wipe_tower_arrangepoly(*this))
fixed.emplace_back(*wt);
arrangement::arrange(movable, fixed, get_bed_shape(*config()),
arrangement::ArrangeParams{min_d});
arrangement::arrange(movable, fixed, get_bed_shape(*config()), arr_params);
for (size_t i = 0; i < instances.size(); ++i)
if (movable[i].bed_idx == 0)
instances[i]->apply_arrange_result(movable[i].translation.cast<double>(),
movable[i].rotation);
for (auto & m : movable)
m.apply();
}
void Plater::priv::split_object()
@ -5024,6 +5057,12 @@ void Plater::convert_unit(ConversionType conv_type)
}
}
void Plater::toggle_layers_editing(bool enable)
{
if (canvas3D()->is_layers_editing_enabled() != enable)
wxPostEvent(canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING));
}
void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper, bool keep_lower, bool rotate_lower)
{
wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds");
@ -5136,6 +5175,30 @@ void Plater::export_stl(bool extended, bool selection_only)
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
return;
// Following lambda generates a combined mesh for export with normals pointing outwards.
auto mesh_to_export = [](const ModelObject* mo, bool instances) -> TriangleMesh {
TriangleMesh mesh;
for (const ModelVolume *v : mo->volumes)
if (v->is_model_part()) {
TriangleMesh vol_mesh(v->mesh());
vol_mesh.repair();
vol_mesh.transform(v->get_matrix(), true);
mesh.merge(vol_mesh);
}
mesh.repair();
if (instances) {
TriangleMesh vols_mesh(mesh);
mesh = TriangleMesh();
for (const ModelInstance *i : mo->instances) {
TriangleMesh m = vols_mesh;
m.transform(i->get_matrix(), true);
mesh.merge(m);
}
}
mesh.repair();
return mesh;
};
TriangleMesh mesh;
if (p->printer_technology == ptFFF) {
if (selection_only) {
@ -5143,20 +5206,21 @@ void Plater::export_stl(bool extended, bool selection_only)
if (selection.get_mode() == Selection::Instance)
{
if (selection.is_single_full_object())
mesh = model_object->mesh();
mesh = mesh_to_export(model_object, true);
else
mesh = model_object->full_raw_mesh();
mesh = mesh_to_export(model_object, false);
}
else
{
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
mesh = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix());
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
mesh.translate(-model_object->origin_translation.cast<float>());
}
}
else {
mesh = p->model.mesh();
for (const ModelObject *o : p->model.objects)
mesh.merge(mesh_to_export(o, true));
}
}
else

View file

@ -202,6 +202,7 @@ public:
bool is_selection_empty() const;
void scale_selection_to_fit_print_volume();
void convert_unit(ConversionType conv_type);
void toggle_layers_editing(bool enable);
void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);
@ -276,7 +277,7 @@ public:
BoundingBoxf bed_shape_bb() const;
void arrange();
void find_new_position(const ModelInstancePtrs &instances, coord_t min_d);
void find_new_position(const ModelInstancePtrs &instances);
void set_current_canvas_as_dirty();
void unbind_canvas_event_handlers();

View file

@ -51,6 +51,9 @@ void PreferencesDialog::build()
auto app_config = get_app_config();
wxNotebook* tabs = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
#ifdef __WXMSW__
tabs->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
// Add "General" tab
m_optgroup_general = create_options_tab(_L("General"), tabs);

View file

@ -86,7 +86,8 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
// Print config values
double layer_height = print_config.opt_float("layer_height");
double first_layer_height = print_config.get_abs_value("first_layer_height", layer_height);
assert(! print_config.option<ConfigOptionFloatOrPercent>("first_layer_height")->percent);
double first_layer_height = print_config.opt_float("first_layer_height");
double support_material_speed = print_config.opt_float("support_material_speed");
double support_material_interface_speed = print_config.get_abs_value("support_material_interface_speed", support_material_speed);
double bridge_speed = print_config.opt_float("bridge_speed");

View file

@ -13,6 +13,7 @@
#include <wx/dataview.h>
#include <wx/wupdlock.h>
#include <wx/debug.h>
#include <wx/msgdlg.h>
#include <boost/log/trivial.hpp>
#include <boost/filesystem.hpp>
@ -68,8 +69,10 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
combo_groups->SetValue(recent_group);
}
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
auto* szr = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
auto* btn_ok = szr->GetAffirmativeButton();
btn_sizer->Add(szr);
wxString recent_path = from_u8(app_config->get("recent", CONFIG_KEY_PATH));
if (recent_path.Length() > 0 && recent_path[recent_path.Length() - 1] != '/') {
recent_path += '/';
@ -82,6 +85,20 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
txt_filename->SetValue(recent_path);
txt_filename->SetFocus();
wxString suffix = recent_path.substr(recent_path.find_last_of('.'));
btn_ok->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) {
wxString path = txt_filename->GetValue();
// .gcode suffix control
if (!path.Lower().EndsWith(suffix.Lower()))
{
wxMessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return;
}
EndDialog(wxID_OK);
});
Fit();
CenterOnParent();

View file

@ -80,7 +80,9 @@ static void unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *con
NSLog(@"-%@",(CFStringRef)deviceModelKey);
*/
if (mediaEjectableKey != nullptr) {
BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital")));
BOOL op = ejectable &&
( (deviceProtocolName != nullptr && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital")))) ||
(deviceModelKey != nullptr && CFEqual(deviceModelKey, CFSTR("SD Card Reader"))) );
//!CFEqual(deviceModelKey, CFSTR("Disk Image"));
if (op)
[result addObject:volURL.path];

View file

@ -1102,39 +1102,32 @@ void Selection::erase()
if (is_single_full_object())
wxGetApp().obj_list()->delete_from_model_and_list(ItemType::itObject, get_object_idx(), 0);
else if (is_multiple_full_object())
{
else if (is_multiple_full_object()) {
std::vector<ItemForDelete> items;
items.reserve(m_cache.content.size());
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it)
{
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it) {
items.emplace_back(ItemType::itObject, it->first, 0);
}
wxGetApp().obj_list()->delete_from_model_and_list(items);
}
else if (is_multiple_full_instance())
{
else if (is_multiple_full_instance()) {
std::set<std::pair<int, int>> instances_idxs;
for (ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.begin(); obj_it != m_cache.content.end(); ++obj_it)
{
for (InstanceIdxsList::reverse_iterator inst_it = obj_it->second.rbegin(); inst_it != obj_it->second.rend(); ++inst_it)
{
for (ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.begin(); obj_it != m_cache.content.end(); ++obj_it) {
for (InstanceIdxsList::reverse_iterator inst_it = obj_it->second.rbegin(); inst_it != obj_it->second.rend(); ++inst_it) {
instances_idxs.insert(std::make_pair(obj_it->first, *inst_it));
}
}
std::vector<ItemForDelete> items;
items.reserve(instances_idxs.size());
for (const std::pair<int, int>& i : instances_idxs)
{
for (const std::pair<int, int>& i : instances_idxs) {
items.emplace_back(ItemType::itInstance, i.first, i.second);
}
wxGetApp().obj_list()->delete_from_model_and_list(items);
}
else if (is_single_full_instance())
wxGetApp().obj_list()->delete_from_model_and_list(ItemType::itInstance, get_object_idx(), get_instance_idx());
else if (is_mixed())
{
else if (is_mixed()) {
std::set<ItemForDelete> items_set;
std::map<int, int> volumes_in_obj;
@ -1186,11 +1179,9 @@ void Selection::erase()
wxGetApp().obj_list()->delete_from_model_and_list(items);
}
else
{
else {
std::set<std::pair<int, int>> volumes_idxs;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* v = (*m_volumes)[i];
// Only remove volumes associated with ModelVolumes from the object list.
// Temporary meshes (SLA supports or pads) are not managed by the object list.
@ -1200,8 +1191,7 @@ void Selection::erase()
std::vector<ItemForDelete> items;
items.reserve(volumes_idxs.size());
for (const std::pair<int, int>& v : volumes_idxs)
{
for (const std::pair<int, int>& v : volumes_idxs) {
items.emplace_back(ItemType::itVolume, v.first, v.second);
}
@ -1214,7 +1204,7 @@ void Selection::render(float scale_factor) const
if (!m_valid || is_empty())
return;
m_scale_factor = scale_factor;
*const_cast<float*>(&m_scale_factor) = scale_factor;
// render cumulative bounding box of selected volumes
render_selected_volumes();
@ -1224,10 +1214,10 @@ void Selection::render(float scale_factor) const
#if ENABLE_RENDER_SELECTION_CENTER
void Selection::render_center(bool gizmo_is_dragging) const
{
if (!m_valid || is_empty() || (m_quadric == nullptr))
if (!m_valid || is_empty() || m_quadric == nullptr)
return;
Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center();
const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center();
glsafe(::glDisable(GL_DEPTH_TEST));
@ -1250,8 +1240,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
GLShaderProgram* shader = nullptr;
if (!boost::starts_with(sidebar_field, "layer"))
{
if (!boost::starts_with(sidebar_field, "layer")) {
shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
@ -1297,7 +1286,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
} else {
glsafe(::glTranslated(center(0), center(1), center(2)));
if (requires_local_axes()) {
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
const Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
}
@ -1735,18 +1724,16 @@ void Selection::do_remove_volume(unsigned int volume_idx)
void Selection::do_remove_instance(unsigned int object_idx, unsigned int instance_idx)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
if (v->object_idx() == (int)object_idx && v->instance_idx() == (int)instance_idx)
do_remove_volume(i);
}
}
void Selection::do_remove_object(unsigned int object_idx)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
GLVolume* v = (*m_volumes)[i];
if (v->object_idx() == (int)object_idx)
do_remove_volume(i);
@ -1755,47 +1742,48 @@ void Selection::do_remove_object(unsigned int object_idx)
void Selection::calc_bounding_box() const
{
m_bounding_box = BoundingBoxf3();
if (m_valid)
{
for (unsigned int i : m_list)
{
m_bounding_box.merge((*m_volumes)[i]->transformed_convex_hull_bounding_box());
BoundingBoxf3* bounding_box = const_cast<BoundingBoxf3*>(&m_bounding_box);
*bounding_box = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
bounding_box->merge((*m_volumes)[i]->transformed_convex_hull_bounding_box());
}
}
m_bounding_box_dirty = false;
*const_cast<bool*>(&m_bounding_box_dirty) = false;
}
void Selection::calc_unscaled_instance_bounding_box() const
{
m_unscaled_instance_bounding_box = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
const GLVolume &volume = *(*m_volumes)[i];
BoundingBoxf3* unscaled_instance_bounding_box = const_cast<BoundingBoxf3*>(&m_unscaled_instance_bounding_box);
*unscaled_instance_bounding_box = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
const GLVolume& volume = *(*m_volumes)[i];
if (volume.is_modifier)
continue;
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix();
trafo.translation()(2) += volume.get_sla_shift_z();
m_unscaled_instance_bounding_box.merge(volume.transformed_convex_hull_bounding_box(trafo));
}
}
m_unscaled_instance_bounding_box_dirty = false;
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix();
trafo.translation()(2) += volume.get_sla_shift_z();
unscaled_instance_bounding_box->merge(volume.transformed_convex_hull_bounding_box(trafo));
}
}
*const_cast<bool*>(&m_unscaled_instance_bounding_box_dirty) = false;
}
void Selection::calc_scaled_instance_bounding_box() const
{
m_scaled_instance_bounding_box = BoundingBoxf3();
BoundingBoxf3* scaled_instance_bounding_box = const_cast<BoundingBoxf3*>(&m_scaled_instance_bounding_box);
*scaled_instance_bounding_box = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
const GLVolume &volume = *(*m_volumes)[i];
const GLVolume& volume = *(*m_volumes)[i];
if (volume.is_modifier)
continue;
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, false, false) * volume.get_volume_transformation().get_matrix();
trafo.translation()(2) += volume.get_sla_shift_z();
m_scaled_instance_bounding_box.merge(volume.transformed_convex_hull_bounding_box(trafo));
scaled_instance_bounding_box->merge(volume.transformed_convex_hull_bounding_box(trafo));
}
}
m_scaled_instance_bounding_box_dirty = false;
*const_cast<bool*>(&m_scaled_instance_bounding_box_dirty) = false;
}
void Selection::render_selected_volumes() const
@ -1988,7 +1976,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
if (pos == std::string::npos)
return;
double min_z = std::stod(field.substr(pos + 1));
const double min_z = std::stod(field.substr(pos + 1));
// extract type
field = field.substr(0, pos);
@ -1996,7 +1984,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
if (pos == std::string::npos)
return;
int type = std::stoi(field.substr(pos + 1));
const int type = std::stoi(field.substr(pos + 1));
const BoundingBoxf3& box = get_bounding_box();
@ -2007,8 +1995,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
// view dependend order of rendering to keep correct transparency
bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward();
float z1 = camera_on_top ? min_z : max_z;
float z2 = camera_on_top ? max_z : min_z;
const float z1 = camera_on_top ? min_z : max_z;
const float z2 = camera_on_top ? max_z : min_z;
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_CULL_FACE));
@ -2016,7 +2004,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
::glBegin(GL_QUADS);
if ((camera_on_top && (type == 1)) || (!camera_on_top && (type == 2)))
if ((camera_on_top && type == 1) || (!camera_on_top && type == 2))
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
else
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
@ -2027,7 +2015,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glEnd());
::glBegin(GL_QUADS);
if ((camera_on_top && (type == 2)) || (!camera_on_top && (type == 1)))
if ((camera_on_top && type == 2) || (!camera_on_top && type == 1))
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
else
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);

View file

@ -206,14 +206,14 @@ private:
IndicesList m_list;
Cache m_cache;
Clipboard m_clipboard;
mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_dirty;
BoundingBoxf3 m_bounding_box;
bool m_bounding_box_dirty;
// Bounding box of a selection, with no instance scaling applied. This bounding box
// is useful for absolute scaling of tilted objects in world coordinate space.
mutable BoundingBoxf3 m_unscaled_instance_bounding_box;
mutable bool m_unscaled_instance_bounding_box_dirty;
mutable BoundingBoxf3 m_scaled_instance_bounding_box;
mutable bool m_scaled_instance_bounding_box_dirty;
BoundingBoxf3 m_unscaled_instance_bounding_box;
bool m_unscaled_instance_bounding_box_dirty;
BoundingBoxf3 m_scaled_instance_bounding_box;
bool m_scaled_instance_bounding_box_dirty;
#if ENABLE_RENDER_SELECTION_CENTER
GLUquadricObj* m_quadric;
@ -222,7 +222,7 @@ private:
GLModel m_arrow;
GLModel m_curved_arrow;
mutable float m_scale_factor;
float m_scale_factor;
public:
Selection();

View file

@ -1002,7 +1002,9 @@ void Tab::sys_color_changed()
for (ScalableBitmap& bmp : m_scaled_icons_list)
m_icons->Add(bmp.bmp());
m_treectrl->AssignImageList(m_icons);
#ifdef __WXMSW__
m_treectrl->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
// Colors for ui "decoration"
update_label_colours();
@ -1516,6 +1518,7 @@ void TabPrint::build()
optgroup->append_single_option_line("support_material_with_sheath", category_path + "with-sheath-around-the-support");
optgroup->append_single_option_line("support_material_spacing", category_path + "pattern-spacing-0-inf");
optgroup->append_single_option_line("support_material_angle", category_path + "pattern-angle");
optgroup->append_single_option_line("support_material_closing_radius", category_path + "pattern-angle");
optgroup->append_single_option_line("support_material_interface_layers", category_path + "interface-layers");
optgroup->append_single_option_line("support_material_bottom_interface_layers", category_path + "interface-layers");
optgroup->append_single_option_line("support_material_interface_pattern", category_path + "interface-pattern");
@ -2273,6 +2276,13 @@ void TabPrinter::build_fff()
m_use_silent_mode = val;
}
}
if (opt_key == "gcode_flavor") {
bool supports_travel_acceleration = (boost::any_cast<int>(value) == int(gcfMarlinFirmware));
if (supports_travel_acceleration != m_supports_travel_acceleration) {
m_rebuild_kinematics_page = true;
m_supports_travel_acceleration = supports_travel_acceleration;
}
}
build_unregular_pages();
update_dirty();
on_value_change(opt_key, value);
@ -2569,6 +2579,8 @@ PageShp TabPrinter::build_kinematics_page()
}
append_option_line(optgroup, "machine_max_acceleration_extruding");
append_option_line(optgroup, "machine_max_acceleration_retracting");
if (m_supports_travel_acceleration)
append_option_line(optgroup, "machine_max_acceleration_travel");
optgroup = page->new_optgroup(L("Jerk limits"));
for (const std::string &axis : axes) {
@ -2591,7 +2603,8 @@ PageShp TabPrinter::build_kinematics_page()
void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/)
{
size_t n_before_extruders = 2; // Count of pages before Extruder pages
bool is_marlin_flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlin;
auto flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
bool is_marlin_flavor = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware);
/* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages
* and be cause of application crash, when try to change Preset in moment,
@ -2861,7 +2874,8 @@ void TabPrinter::toggle_options()
if (m_active_page->title() == "General") {
toggle_option("single_extruder_multi_material", have_multiple_extruders);
bool is_marlin_flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlin;
auto flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware;
// Disable silent mode for non-marlin firmwares.
toggle_option("silent_mode", is_marlin_flavor);
}
@ -2929,7 +2943,8 @@ void TabPrinter::toggle_options()
}
if (m_active_page->title() == "Machine limits" && m_machine_limits_description_line) {
assert(m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlin);
assert(m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlinLegacy
|| m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlinFirmware);
const auto *machine_limits_usage = m_config->option<ConfigOptionEnum<MachineLimitsUsage>>("machine_limits_usage");
bool enabled = machine_limits_usage->value != MachineLimitsUsage::Ignore;
bool silent_mode = m_config->opt_bool("silent_mode");
@ -2960,6 +2975,12 @@ void TabPrinter::update_fff()
m_use_silent_mode = m_config->opt_bool("silent_mode");
}
bool supports_travel_acceleration = (m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlinFirmware);
if (m_supports_travel_acceleration != supports_travel_acceleration) {
m_rebuild_kinematics_page = true;
m_supports_travel_acceleration = supports_travel_acceleration;
}
toggle_options();
}

View file

@ -443,6 +443,7 @@ class TabPrinter : public Tab
private:
bool m_has_single_extruder_MM_page = false;
bool m_use_silent_mode = false;
bool m_supports_travel_acceleration = false;
void append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key);
bool m_rebuild_kinematics_page = false;
ogStaticText* m_machine_limits_description_line {nullptr};

View file

@ -590,6 +590,9 @@ void LockButton::msw_rescale()
void LockButton::update_button_bitmaps()
{
#ifdef __WXMSW__
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
SetBitmap(m_is_pushed ? m_bmp_lock_closed.bmp() : m_bmp_lock_open.bmp());
SetBitmapHover(m_is_pushed ? m_bmp_lock_closed_f.bmp() : m_bmp_lock_open_f.bmp());
@ -885,6 +888,9 @@ void ScalableButton::UseDefaultBitmapDisabled()
void ScalableButton::msw_rescale()
{
#ifdef __WXMSW__
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
SetBitmap(create_scaled_bitmap(m_current_icon_name, m_parent, m_px_cnt));
if (!m_disabled_icon_name.empty())
SetBitmapDisabled(create_scaled_bitmap(m_disabled_icon_name, m_parent, m_px_cnt));