mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 17:21:11 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_custom_gcode_detection
This commit is contained in:
commit
c7771a576b
73 changed files with 2263 additions and 2165 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);
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" })
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -508,6 +508,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 +518,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 +528,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 +568,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;
|
||||
|
|
@ -3524,7 +3528,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)
|
||||
|
|
@ -3541,22 +3545,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)
|
||||
|
|
@ -3572,8 +3573,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);
|
||||
|
|
@ -3932,13 +3932,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;
|
||||
}
|
||||
|
|
@ -3979,9 +3979,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;
|
||||
|
|
@ -4840,8 +4841,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.
|
||||
|
|
@ -4856,9 +4859,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();
|
||||
|
|
@ -4884,11 +4888,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();
|
||||
}
|
||||
|
|
@ -4896,12 +4900,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));
|
||||
|
|
@ -4922,8 +4925,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
|
||||
|
|
@ -4943,7 +4945,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();
|
||||
|
|
@ -4958,14 +4960,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();
|
||||
}
|
||||
|
||||
|
|
@ -5059,7 +5061,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.
|
||||
|
|
@ -5067,17 +5071,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) {
|
||||
|
|
@ -5085,16 +5089,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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -5112,11 +5116,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
|
||||
|
|
@ -5157,13 +5161,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
|
||||
|
||||
|
|
@ -5211,13 +5215,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
|
||||
|
||||
|
|
@ -5292,12 +5296,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();
|
||||
|
|
@ -5316,8 +5320,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
|
||||
|
|
@ -5332,8 +5337,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
|
||||
|
|
@ -5424,20 +5431,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();
|
||||
}
|
||||
|
|
@ -5543,7 +5551,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;
|
||||
}
|
||||
|
||||
|
|
@ -5567,7 +5575,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;
|
||||
}
|
||||
|
||||
|
|
@ -5588,23 +5596,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6311,31 +6311,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1525,14 +1525,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))
|
||||
|
|
@ -1540,9 +1546,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)
|
||||
|
|
@ -2118,20 +2125,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;
|
||||
|
|
@ -2243,6 +2262,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];
|
||||
|
|
@ -2251,6 +2316,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) {
|
||||
|
|
@ -3029,7 +3096,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);
|
||||
|
|
@ -3442,6 +3509,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);
|
||||
|
|
|
|||
|
|
@ -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,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;
|
||||
|
|
|
|||
|
|
@ -522,8 +522,10 @@ void MainFrame::init_tabpanel()
|
|||
#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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2407,6 +2407,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));
|
||||
|
|
@ -2425,6 +2448,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();
|
||||
}
|
||||
|
|
@ -4943,6 +4967,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");
|
||||
|
|
|
|||
|
|
@ -191,6 +191,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,7 +1214,7 @@ 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();
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1515,6 +1515,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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue