mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-06 05:24:01 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_project_dirty_state
This commit is contained in:
commit
ede14251b1
199 changed files with 11027 additions and 6477 deletions
|
@ -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) {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" })
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -46,6 +46,9 @@ class GCodeViewer
|
|||
{
|
||||
Retractions,
|
||||
Unretractions,
|
||||
#if ENABLE_SEAMS_VISUALIZATION
|
||||
Seams,
|
||||
#endif // ENABLE_SEAMS_VISUALIZATION
|
||||
ToolChanges,
|
||||
ColorChanges,
|
||||
PausePrints,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"); }
|
||||
|
|
|
@ -116,6 +116,9 @@ public:
|
|||
Wipe,
|
||||
Retractions,
|
||||
Unretractions,
|
||||
#if ENABLE_SEAMS_VISUALIZATION
|
||||
Seams,
|
||||
#endif // ENABLE_SEAMS_VISUALIZATION
|
||||
ToolChanges,
|
||||
ColorChanges,
|
||||
PausePrints,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 ¶ms)>;
|
||||
|
||||
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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue