From fa1ff1c35768e09fdb7270f563f62abb558cd966 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 10 Feb 2022 14:39:02 +0100 Subject: [PATCH 01/27] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Another refactoring to simplify client code of GLModel::Geometry --- src/slic3r/GUI/3DBed.cpp | 10 ++++------ src/slic3r/GUI/3DScene.cpp | 5 ++--- src/slic3r/GUI/GLCanvas3D.cpp | 5 ++--- src/slic3r/GUI/GLModel.cpp | 5 +++++ src/slic3r/GUI/GLModel.hpp | 12 +++++++----- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 5 ++--- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 5 ++--- src/slic3r/GUI/MeshUtils.cpp | 5 ++--- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 8488c1148..0facce33c 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -312,8 +312,7 @@ void Bed3D::init_triangles() return; GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, GLModel::Geometry::index_type(triangles.size()) }; init_data.reserve_vertices(triangles.size()); init_data.reserve_indices(triangles.size() / 3); @@ -338,7 +337,7 @@ void Bed3D::init_triangles() init_data.add_vertex(p, (Vec2f)v.cwiseProduct(inv_size).eval()); ++vertices_counter; if (vertices_counter % 3 == 0) { - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); else init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); @@ -381,8 +380,7 @@ void Bed3D::init_gridlines() std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (2 * gridlines.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * gridlines.size()) }; init_data.reserve_vertices(2 * gridlines.size()); init_data.reserve_indices(2 * gridlines.size()); @@ -390,7 +388,7 @@ void Bed3D::init_gridlines() init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), GROUND_Z)); init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), GROUND_Z)); const unsigned int vertices_counter = (unsigned int)init_data.vertices_count(); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); else init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 339754790..c9b647b07 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -400,8 +400,7 @@ void GLVolume::NonManifoldEdges::update() if (!edges.empty()) { GUI::GLModel::Geometry init_data; #if ENABLE_GLBEGIN_GLEND_REMOVAL - const GUI::GLModel::Geometry::EIndexType index_type = (2 * edges.size() < 65536) ? GUI::GLModel::Geometry::EIndexType::USHORT : GUI::GLModel::Geometry::EIndexType::UINT; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Lines, GUI::GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Lines, GUI::GLModel::Geometry::EVertexLayout::P3, GUI::GLModel::Geometry::index_type(2 * edges.size()) }; init_data.reserve_vertices(2 * edges.size()); init_data.reserve_indices(2 * edges.size()); @@ -411,7 +410,7 @@ void GLVolume::NonManifoldEdges::update() init_data.add_vertex((Vec3f)mesh.its.vertices[edge.first].cast()); init_data.add_vertex((Vec3f)mesh.its.vertices[edge.second].cast()); vertices_count += 2; - if (index_type == GUI::GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GUI::GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); else init_data.add_uint_line(vertices_count - 2, vertices_count - 1); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 95600c074..ee16aefef 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -447,8 +447,7 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) m_profile.profile.reset(); GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (m_layer_height_profile.size() / 2 < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::index_type(m_layer_height_profile.size() / 2) }; init_data.color = ColorRGBA::BLUE(); init_data.reserve_vertices(m_layer_height_profile.size() / 2); init_data.reserve_indices(m_layer_height_profile.size() / 2); @@ -457,7 +456,7 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y)); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_index((unsigned short)i / 2); else init_data.add_uint_index(i / 2); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index e1dc3305c..28a6a1ce7 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -328,6 +328,11 @@ size_t GLModel::Geometry::index_stride_bytes(const Format& format) }; } +GLModel::Geometry::EIndexType GLModel::Geometry::index_type(size_t vertices_count) +{ + return (vertices_count < 65536) ? EIndexType::USHORT : EIndexType::UINT; +} + bool GLModel::Geometry::has_position(const Format& format) { switch (format.vertex_layout) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 70220a75c..72c50ee11 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -83,11 +83,11 @@ namespace GUI { void reserve_vertices(size_t vertices_count); void reserve_indices(size_t indices_count); - void add_vertex(const Vec2f& position); - void add_vertex(const Vec2f& position, const Vec2f& tex_coord); - void add_vertex(const Vec3f& position); - void add_vertex(const Vec3f& position, const Vec2f& tex_coord); - void add_vertex(const Vec3f& position, const Vec3f& normal); + void add_vertex(const Vec2f& position); // EVertexLayout::P2 + void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 + void add_vertex(const Vec3f& position); // EVertexLayout::P3 + void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 + void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 void add_ushort_index(unsigned short id); void add_uint_index(unsigned int id); @@ -135,6 +135,8 @@ namespace GUI { static size_t index_stride_bytes(const Format& format); + static EIndexType index_type(size_t vertices_count); + static bool has_position(const Format& format); static bool has_normal(const Format& format); static bool has_tex_coord(const Format& format); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 0956a9047..ea15deb16 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -362,14 +362,13 @@ void GLGizmoFlatten::update_planes() for (auto& plane : m_planes) { #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (plane.vertices.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(plane.vertices.size()) }; init_data.reserve_vertices(plane.vertices.size()); init_data.reserve_indices(plane.vertices.size()); // vertices + indices for (size_t i = 0; i < plane.vertices.size(); ++i) { init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_index((unsigned short)i); else init_data.add_uint_index((unsigned int)i); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 0fc57c909..82a816d1b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1189,8 +1189,7 @@ void TriangleSelectorGUI::update_paint_contour() GLModel::Geometry init_data; const std::vector contour_edges = this->get_seed_fill_contour(); - const GLModel::Geometry::EIndexType index_type = (2 * contour_edges.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * contour_edges.size()) }; init_data.reserve_vertices(2 * contour_edges.size()); init_data.reserve_indices(2 * contour_edges.size()); // vertices + indices @@ -1199,7 +1198,7 @@ void TriangleSelectorGUI::update_paint_contour() init_data.add_vertex(m_vertices[edge(0)].v); init_data.add_vertex(m_vertices[edge(1)].v); vertices_count += 2; - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); else init_data.add_uint_line(vertices_count - 2, vertices_count - 1); diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 68762c67a..3787abb2f 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -189,8 +189,7 @@ void MeshClipper::recalculate_triangles() m_model.reset(); GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (m_triangles2d.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(m_triangles2d.size()) }; init_data.reserve_vertices(m_triangles2d.size()); init_data.reserve_indices(m_triangles2d.size()); @@ -200,7 +199,7 @@ void MeshClipper::recalculate_triangles() init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); const size_t idx = it - m_triangles2d.cbegin(); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); else init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); From a28dea0617d0342c79cadf99f64f72b5d06d0286 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 10 Feb 2022 15:11:22 +0100 Subject: [PATCH 02/27] Follow-up of 6b041429f6f137add530c900c3160d431286366f - Fixed uvmapping of printbed texture --- src/slic3r/GUI/3DBed.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 0facce33c..244a802db 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -334,7 +334,7 @@ void Bed3D::init_triangles() unsigned int vertices_counter = 0; for (const Vec2f& v : triangles) { const Vec3f p = { v.x(), v.y(), GROUND_Z }; - init_data.add_vertex(p, (Vec2f)v.cwiseProduct(inv_size).eval()); + init_data.add_vertex(p, (Vec2f)(v - min).cwiseProduct(inv_size).eval()); ++vertices_counter; if (vertices_counter % 3 == 0) { if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) From aa4714a239d9d224708156c6c15a0d239a7c8a71 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 10 Feb 2022 15:17:24 +0100 Subject: [PATCH 03/27] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Removed OpenGL legacy calls from GLCanvas3D::init() --- src/slic3r/GUI/GLCanvas3D.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ee16aefef..398eef1de 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1157,6 +1157,7 @@ bool GLCanvas3D::init() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); +#if !ENABLE_GLBEGIN_GLEND_REMOVAL // Set antialiasing / multisampling glsafe(::glDisable(GL_LINE_SMOOTH)); glsafe(::glDisable(GL_POLYGON_SMOOTH)); @@ -1186,6 +1187,7 @@ bool GLCanvas3D::init() // A handy trick -- have surface material mirror the color. glsafe(::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)); glsafe(::glEnable(GL_COLOR_MATERIAL)); +#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); @@ -5868,11 +5870,11 @@ void GLCanvas3D::_render_sla_slices() if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { for (const SLAPrintObject::Instance& inst : obj->instances()) { glsafe(::glPushMatrix()); - glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0)); - glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0)); + glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); + glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); if (obj->is_left_handed()) // The polygons are mirrored by X. - glsafe(::glScalef(-1.0, 1.0, 1.0)); + glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glColor3f(1.0f, 0.37f, 0.0f)); if (!bottom_obj_triangles.empty()) { From c9ff260d13690eb32527900599487712a77e1657 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 11 Feb 2022 09:15:56 +0100 Subject: [PATCH 04/27] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - SLA caps rendered using GLModel --- src/slic3r/GUI/GLCanvas3D.cpp | 100 ++++++++++++++++++++++++++++++++-- src/slic3r/GUI/GLCanvas3D.hpp | 13 ++++- 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 398eef1de..db15bdce5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5802,32 +5802,81 @@ void GLCanvas3D::_render_sla_slices() if (!obj->is_step_done(slaposSliceSupports)) continue; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + SlaCap::ObjectIdToModelsMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); + SlaCap::ObjectIdToModelsMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); +#else 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); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL { 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 ENABLE_GLBEGIN_GLEND_REMOVAL + it_caps_bottom->second.object.reset(); + it_caps_bottom->second.supports.reset(); +#else it_caps_bottom->second.object.clear(); it_caps_bottom->second.supports.clear(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } 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 ENABLE_GLBEGIN_GLEND_REMOVAL + it_caps_top->second.object.reset(); + it_caps_top->second.supports.reset(); +#else it_caps_top->second.object.clear(); it_caps_top->second.supports.clear(); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLModel& bottom_obj_triangles = it_caps_bottom->second.object; + GLModel& bottom_sup_triangles = it_caps_bottom->second.supports; + GLModel& top_obj_triangles = it_caps_top->second.object; + GLModel& top_sup_triangles = it_caps_top->second.supports; +#else Pointf3s &bottom_obj_triangles = it_caps_bottom->second.object; Pointf3s &bottom_sup_triangles = it_caps_bottom->second.supports; Pointf3s &top_obj_triangles = it_caps_top->second.object; Pointf3s &top_sup_triangles = it_caps_top->second.supports; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL +#if ENABLE_GLBEGIN_GLEND_REMOVAL + auto init_model = [](GLModel& model, const Pointf3s& triangles, const ColorRGBA& color) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(triangles.size()) }; + init_data.reserve_vertices(triangles.size()); + init_data.reserve_indices(triangles.size() / 3); + init_data.color = color; + + unsigned int vertices_count = 0; + for (const Vec3d& v : triangles) { + init_data.add_vertex((Vec3f)v.cast()); + ++vertices_count; + if (vertices_count % 3 == 0) { + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)vertices_count - 3, (unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); + else + init_data.add_uint_triangle(vertices_count - 3, vertices_count - 2, vertices_count - 1); + } + } + + if (!init_data.is_empty()) + model.init_from(std::move(init_data)); + }; + + if ((!bottom_obj_triangles.is_initialized() || !bottom_sup_triangles.is_initialized() || + !top_obj_triangles.is_initialized() || !top_sup_triangles.is_initialized()) && !obj->get_slice_index().empty()) { +#else if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - !obj->get_slice_index().empty()) - { + !obj->get_slice_index().empty()) { +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value; bool left_handed = obj->is_left_handed(); @@ -5842,31 +5891,73 @@ void GLCanvas3D::_render_sla_slices() const SliceRecord& slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON)); // Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts. - double plane_shift_z = 0.002; + const double plane_shift_z = 0.002; if (slice_low.is_valid()) { const ExPolygons& obj_bottom = slice_low.get_slice(soModel); const ExPolygons& sup_bottom = slice_low.get_slice(soSupport); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + // calculate model bottom cap + if (!bottom_obj_triangles.is_initialized() && !obj_bottom.empty()) + init_model(bottom_obj_triangles, triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.37f, 0.0f, 1.0f }); + // calculate support bottom cap + if (!bottom_sup_triangles.is_initialized() && !sup_bottom.empty()) + init_model(bottom_sup_triangles, triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.0f, 0.37f, 1.0f }); +#else // calculate model bottom cap if (bottom_obj_triangles.empty() && !obj_bottom.empty()) bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed); // calculate support bottom cap if (bottom_sup_triangles.empty() && !sup_bottom.empty()) - bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed); + bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } if (slice_high.is_valid()) { const ExPolygons& obj_top = slice_high.get_slice(soModel); const ExPolygons& sup_top = slice_high.get_slice(soSupport); +#if ENABLE_GLBEGIN_GLEND_REMOVAL + // calculate model top cap + if (!top_obj_triangles.is_initialized() && !obj_top.empty()) + init_model(top_obj_triangles, triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.37f, 0.0f, 1.0f }); + // calculate support top cap + if (!top_sup_triangles.is_initialized() && !sup_top.empty()) + init_model(top_sup_triangles, triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.0f, 0.37f, 1.0f }); +#else // calculate model top cap if (top_obj_triangles.empty() && !obj_top.empty()) top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed); // calculate support top cap if (top_sup_triangles.empty() && !sup_top.empty()) top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + for (const SLAPrintObject::Instance& inst : obj->instances()) { + glsafe(::glPushMatrix()); + glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); + glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); + if (obj->is_left_handed()) + // The polygons are mirrored by X. + glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); + + bottom_obj_triangles.render(); + top_obj_triangles.render(); + bottom_sup_triangles.render(); + top_sup_triangles.render(); + + glsafe(::glPopMatrix()); + } + + shader->stop_using(); + } +#else if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { for (const SLAPrintObject::Instance& inst : obj->instances()) { glsafe(::glPushMatrix()); @@ -5898,6 +5989,7 @@ void GLCanvas3D::_render_sla_slices() glsafe(::glPopMatrix()); } } +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 33e17d5dd..57f173c7b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -335,6 +335,16 @@ class GLCanvas3D struct SlaCap { +#if ENABLE_GLBEGIN_GLEND_REMOVAL + struct Triangles + { + GLModel object; + GLModel supports; + }; + typedef std::map ObjectIdToModelsMap; + double z; + ObjectIdToModelsMap triangles; +#else struct Triangles { Pointf3s object; @@ -343,6 +353,7 @@ class GLCanvas3D typedef std::map ObjectIdToTrianglesMap; double z; ObjectIdToTrianglesMap triangles; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL SlaCap() { reset(); } void reset() { z = DBL_MAX; triangles.clear(); } @@ -473,7 +484,7 @@ private: std::array m_clipping_planes; ClippingPlane m_camera_clipping_plane; bool m_use_clipping_planes; - SlaCap m_sla_caps[2]; + std::array m_sla_caps; std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false // see request_extra_frame() From 0c74081f7dd33ebeb4e6f2c179e728520b19febb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 11 Feb 2022 11:29:00 +0100 Subject: [PATCH 05/27] Follow-up of afcac6e2ea306fbbb12428e360c0fe70b2a3f12d - Fixed GLGizmoSlaSupports::render_points() --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 3406c58a2..fa0b27269 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -127,6 +127,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (! has_points && ! has_holes) return; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + ScopeGuard guard([shader]() { shader->stop_using(); }); +#else GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) shader->start_using(); @@ -134,6 +142,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (shader != nullptr) shader->stop_using(); }); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); @@ -177,11 +186,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) #if ENABLE_GLBEGIN_GLEND_REMOVAL m_cone.set_color(render_color); m_sphere.set_color(render_color); + if (!picking) #else m_cone.set_color(-1, render_color); m_sphere.set_color(-1, render_color); -#endif // ENABLE_GLBEGIN_GLEND_REMOVAL if (shader && !picking) +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL shader->set_uniform("emission_factor", 0.5f); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. @@ -236,9 +246,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) m_cylinder.set_color(render_color); #else m_cylinder.set_color(-1, render_color); + if (shader != nu) #endif // ENABLE_GLBEGIN_GLEND_REMOVAL - if (shader) - shader->set_uniform("emission_factor", 0.5f); + shader->set_uniform("emission_factor", 0.5f); for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { if (is_mesh_point_clipped(drain_hole.pos.cast())) continue; From a1ff2bb7d7a3c26d3f4341e9fe1f4d47fad50e67 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 11 Feb 2022 11:38:36 +0100 Subject: [PATCH 06/27] Fix for #6364 - MacOS / Minimize window / Shortcut CMD + M There was a bug in wxWidgets 3.1.4. (wxWidgets/wxWidgets#18998) So, we cherry-picked fixing commit from the upstream wxWidgets to our "v3.1.4-patched" Note: It's update of the Sha256 for wxWidgets in master branch --- deps/wxWidgets/wxWidgets.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 2730854eb..1ca6735cc 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -12,8 +12,8 @@ endif() prusaslicer_add_cmake_project(wxWidgets # GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" # GIT_TAG tm_cross_compile #${_wx_git_tag} - URL https://github.com/prusa3d/wxWidgets/archive/73f029adfcc82fb3aa4b01220a013f716e57d110.zip - URL_HASH SHA256=c35fe0187db497b6a3f477e24ed5e307028657ff0c2554385810b6e7961ad2e4 + URL https://github.com/prusa3d/wxWidgets/archive/489f6118256853cf5b299d595868641938566cdb.zip + URL_HASH SHA256=5b22d465377cedd8044bba69bea958b248953fd3628c1de4913a84d4e6f6175b DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG CMAKE_ARGS -DwxBUILD_PRECOMP=ON From 5089d1460d172e29164e313e806457181a67daef Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 11 Feb 2022 11:47:29 +0100 Subject: [PATCH 07/27] Removed obsolete member variable GLCanvas3D::m_color_by --- src/slic3r/GUI/3DScene.cpp | 8 ++------ src/slic3r/GUI/3DScene.hpp | 2 -- src/slic3r/GUI/GCodeViewer.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++-------- src/slic3r/GUI/GLCanvas3D.hpp | 4 ---- 5 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index c9b647b07..23ca974dd 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -684,13 +684,12 @@ std::vector GLVolumeCollection::load_object( const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, - const std::string &color_by, bool opengl_initialized) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized)); return volumes_idx; } @@ -699,16 +698,13 @@ int GLVolumeCollection::load_object_volume( int obj_idx, int volume_idx, int instance_idx, - const std::string &color_by, bool opengl_initialized) { const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; const TriangleMesh &mesh = model_volume->mesh(); - ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4]; - color.a(model_volume->is_model_part() ? 1.0f : 0.5f); - this->volumes.emplace_back(new GLVolume(color)); + this->volumes.emplace_back(new GLVolume()); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); #if ENABLE_SMOOTH_NORMALS diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 5aaa759f2..c2e4e587c 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -593,7 +593,6 @@ public: const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, - const std::string &color_by, bool opengl_initialized); int load_object_volume( @@ -601,7 +600,6 @@ public: int obj_idx, int volume_idx, int instance_idx, - const std::string &color_by, bool opengl_initialized); // Load SLA auxiliary GLVolumes (for support trees or pad). diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index d54c28293..c86d16a1f 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -2306,7 +2306,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized) } size_t current_volumes_count = m_shells.volumes.volumes.size(); - m_shells.volumes.load_object(model_obj, object_id, instance_ids, "object", initialized); + m_shells.volumes.load_object(model_obj, object_id, instance_ids, initialized); // adjust shells' z if raft is present const SlicingParameters& slicing_parameters = obj->slicing_parameters(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index db15bdce5..732c75589 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1106,7 +1106,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_moving(false) , m_tab_down(false) , m_cursor_type(Standard) - , m_color_by("volume") , m_reload_delayed(false) #if ENABLE_RENDER_PICKING_PASS , m_show_picking_texture(false) @@ -1358,11 +1357,6 @@ void GLCanvas3D::bed_shape_changed() m_dirty = true; } -void GLCanvas3D::set_color_by(const std::string& value) -{ - m_color_by = value; -} - void GLCanvas3D::refresh_camera_scene_box() { wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); @@ -1807,7 +1801,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.emplace_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -2032,7 +2026,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // later in this function. it->volume_idx = m_volumes.volumes.size(); - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 57f173c7b..a3c302bae 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -522,8 +522,6 @@ private: // I just don't want to do it now before a release (Lukas Matena 24.3.2019) bool m_render_sla_auxiliaries; - std::string m_color_by; - bool m_reload_delayed; #if ENABLE_RENDER_PICKING_PASS @@ -692,8 +690,6 @@ public: bool get_use_clipping_planes() const { return m_use_clipping_planes; } const std::array &get_clipping_planes() const { return m_clipping_planes; }; - void set_color_by(const std::string& value); - void refresh_camera_scene_box(); BoundingBoxf3 volumes_bounding_box() const; From 0835e117d588f98da14c0636ad514882ee9313f3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 11 Feb 2022 12:06:48 +0100 Subject: [PATCH 08/27] Refactoring in GLCanvas3D::LayersEditing::render_volumes() --- src/slic3r/GUI/GLCanvas3D.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 732c75589..edd62ce0a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -495,17 +495,17 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G { assert(this->is_allowed()); assert(this->last_object_id != -1); + + GLShaderProgram* current_shader = wxGetApp().get_current_shader(); + ScopeGuard guard([current_shader]() { if (current_shader != nullptr) current_shader->start_using(); }); + if (current_shader != nullptr) + current_shader->stop_using(); + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); if (shader == nullptr) return; - GLShaderProgram* current_shader = wxGetApp().get_current_shader(); - if (shader->get_id() != current_shader->get_id()) - // The layer editing shader is not yet active. Activate it. - shader->start_using(); - else - // The layer editing shader was already active. - current_shader = nullptr; + shader->start_using(); generate_layer_height_texture(); @@ -516,10 +516,10 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G shader->set_uniform("z_cursor_band_width", float(this->band_width)); // Initialize the layer height texture mapping. - GLsizei w = (GLsizei)m_layers_texture.width; - GLsizei h = (GLsizei)m_layers_texture.height; - GLsizei half_w = w / 2; - GLsizei half_h = h / 2; + const GLsizei w = (GLsizei)m_layers_texture.width; + const GLsizei h = (GLsizei)m_layers_texture.height; + const GLsizei half_w = w / 2; + const GLsizei half_h = h / 2; glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); @@ -528,17 +528,15 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4)); for (const GLVolume* glvolume : volumes.volumes) { // Render the object using the layer editing shader and texture. - if (! glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) + if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) continue; shader->set_uniform("volume_world_matrix", glvolume->world_matrix()); - shader->set_uniform("object_max_z", GLfloat(0)); + shader->set_uniform("object_max_z", 0.0f); glvolume->render(); } // Revert back to the previous shader. glBindTexture(GL_TEXTURE_2D, 0); - if (current_shader != nullptr) - current_shader->start_using(); } void GLCanvas3D::LayersEditing::adjust_layer_height_profile() From 7685e707434613e1a8ba50a189da61061e1a26d0 Mon Sep 17 00:00:00 2001 From: ole00 Date: Fri, 11 Feb 2022 22:06:47 +0000 Subject: [PATCH 09/27] SLA: added pwmx format exporter Pwmx format is used by Anycubic Photon Mono X printers. File format structure and rle encoding implemented according to: https://github.com/sn4k3/UVtools https://github.com/ole00/pwmx_info --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Format/pwmx.cpp | 509 ++++++++++++++++++++ src/libslic3r/Format/pwmx.hpp | 36 ++ src/libslic3r/SLA/RasterBase.cpp | 48 ++ src/libslic3r/SLA/RasterBase.hpp | 4 + src/libslic3r/SLAPrint.cpp | 18 + src/libslic3r/SLAPrint.hpp | 38 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 26 +- src/slic3r/GUI/GUI_App.cpp | 2 +- 9 files changed, 647 insertions(+), 36 deletions(-) create mode 100644 src/libslic3r/Format/pwmx.cpp create mode 100644 src/libslic3r/Format/pwmx.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d4c8d7edc..ea663f2e1 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -98,6 +98,8 @@ set(SLIC3R_SOURCES Format/SL1.cpp Format/SL1_SVG.hpp Format/SL1_SVG.cpp + Format/pwmx.hpp + Format/pwmx.cpp GCode/ThumbnailData.cpp GCode/ThumbnailData.hpp GCode/Thumbnails.cpp diff --git a/src/libslic3r/Format/pwmx.cpp b/src/libslic3r/Format/pwmx.cpp new file mode 100644 index 000000000..99785b8d0 --- /dev/null +++ b/src/libslic3r/Format/pwmx.cpp @@ -0,0 +1,509 @@ +#include "pwmx.hpp" +#include "GCode/ThumbnailData.hpp" + +#include +#include +#include + + +#define TAG_INTRO "ANYCUBIC\0\0\0\0" +#define TAG_HEADER "HEADER\0\0\0\0\0\0" +#define TAG_PREVIEW "PREVIEW\0\0\0\0\0" +#define TAG_LAYERS "LAYERDEF\0\0\0\0" + +#define CFG_LIFT_DISTANCE "LIFT_DISTANCE" +#define CFG_LIFT_SPEED "LIFT_SPEED" +#define CFG_RETRACT_SPEED "RETRACT_SPEED" +#define CFG_DELAY_BEFORE_EXPOSURE "DELAY_BEFORE_EXPOSURE" +#define CFG_BOTTOM_LIFT_SPEED "BOTTOM_LIFT_SPEED" +#define CFG_BOTTOM_LIFT_DISTANCE "BOTTOM_LIFT_DISTANCE" + +#define PREV_W 224 +#define PREV_H 168 +#define PREV_DPI 42 + +#define LAYER_SIZE_ESTIMATE (32 * 1024) + + +namespace Slic3r { + +using ConfMap = std::map; + +typedef struct pwmx_format_intro +{ + char tag[12]; + std::uint32_t version; // value 1 + std::uint32_t area_num; // unknown - usually 4 + std::uint32_t header_data_offset; + std::float_t intro24; // unknown - usually 0 + std::uint32_t preview_data_offset; + std::float_t intro32; // unknown + std::uint32_t layer_data_offset; + std::float_t intro40; // unknown + std::uint32_t image_data_offset; +} pwmx_format_intro; + +typedef struct pwmx_format_header +{ + char tag[12]; + std::uint32_t payload_size; + std::float_t pixel_size_um; + std::float_t layer_height_mm; + std::float_t exposure_time_s; + std::float_t delay_before_exposure_s; + std::float_t bottom_exposure_time_s; + std::float_t bottom_layer_count; + std::float_t lift_distance_mm; + std::float_t lift_speed_mms; + std::float_t retract_speed_mms; + std::float_t volume_ml; + std::uint32_t antialiasing; + std::uint32_t res_x; + std::uint32_t res_y; + std::float_t weight_g; + std::float_t price; + std::uint32_t price_currency; + std::uint32_t per_layer_override; // ? unknown meaning ? + std::uint32_t print_time_s; + std::uint32_t transition_layer_count; + std::uint32_t unknown; // ? usually 0 ? + +} pwmx_format_header; + +typedef struct pwmx_format_preview +{ + char tag[12]; + std::uint32_t payload_size; + std::uint32_t preview_w; + std::uint32_t preview_dpi; + std::uint32_t preview_h; + // raw image data in BGR565 format + std::uint8_t pixels[PREV_W * PREV_H * 2]; +} pwmx_format_preview; + +typedef struct pwmx_format_layers_header +{ + char tag[12]; + std::uint32_t payload_size; + std::uint32_t layer_count; +} pwmx_format_layers_header; + +typedef struct pwmx_format_layer +{ + std::uint32_t image_offset; + std::uint32_t image_size; + std::float_t lift_distance_mm; + std::float_t lift_speed_mms; + std::float_t exposure_time_s; + std::float_t layer_height_mm; + std::float_t layer44; // unkown - usually 0 + std::float_t layer48; // unkown - usually 0 +} pwmx_format_layer; + +typedef struct pwmx_format_misc +{ + std::float_t bottom_layer_height_mm; + std::float_t bottom_lift_distance_mm; + std::float_t bottom_lift_speed_mms; + +} pwmx_format_misc; + +class PwmxFormatConfigDef : public ConfigDef +{ +public: + PwmxFormatConfigDef() + { + add(CFG_LIFT_DISTANCE, coFloat); + add(CFG_LIFT_SPEED, coFloat); + add(CFG_RETRACT_SPEED, coFloat); + add(CFG_DELAY_BEFORE_EXPOSURE, coFloat); + add(CFG_BOTTOM_LIFT_DISTANCE, coFloat); + add(CFG_BOTTOM_LIFT_SPEED, coFloat); + } +}; + +class PwmxFormatDynamicConfig : public DynamicConfig +{ +public: + PwmxFormatDynamicConfig(){}; + const ConfigDef *def() const override { return &config_def; } + +private: + PwmxFormatConfigDef config_def; +}; + +namespace { + +const char *get_cfg_value(const DynamicConfig &cfg, + const std::string & key, + const std::string & def = "0") +{ + std::string ret; + + if (cfg.has(key)) { + auto opt = cfg.option(key); + if (opt) { + ret = opt->serialize(); + } else { + return def.c_str(); + } + } else { + return def.c_str(); + } + + return ret.c_str(); +} + +template void crop_value(T &val, T val_min, T val_max) +{ + if (val < val_min) { + val = val_min; + } else if (val > val_max) { + val = val_max; + } +} + +void fill_preview(pwmx_format_preview &p, + pwmx_format_misc &m, + ThumbnailsList &thumbnails) +{ + + p.preview_w = PREV_W; + p.preview_h = PREV_H; + p.preview_dpi = PREV_DPI; + p.payload_size = sizeof(p) - sizeof(p.tag) - sizeof(p.payload_size); + + std::memset(p.pixels, 0 , sizeof(p.pixels)); + if (!thumbnails.empty()) { + std::uint32_t dst_index; + std::uint32_t i = 0; + size_t len; + size_t pixel_x = 0; + auto t = thumbnails[0]; //use the first thumbnail + len = t.pixels.size(); + //sanity check + if (len != PREV_W * PREV_H * 4) { + printf("incorrect thumbnail size. expected %ix%i\n", PREV_W, PREV_H); + return; + } + // rearange pixels: they seem to be stored from bottom to top. + dst_index = (PREV_W * (PREV_H - 1) * 2); + while (i < len) { + std::uint32_t pixel; + std::uint32_t r = t.pixels[i++]; + std::uint32_t g = t.pixels[i++]; + std::uint32_t b = t.pixels[i++]; + i++; // Alpha + // convert to BGRA565 + pixel = ((b >> 3) << 11) | ((g >>2) << 5) | (r >> 3); + p.pixels[dst_index++] = pixel & 0xFF; + p.pixels[dst_index++] = (pixel >> 8) & 0xFF; + pixel_x++; + if (pixel_x == PREV_W) { + pixel_x = 0; + dst_index -= (PREV_W * 4); + } + } + } +} + + +void fill_header(pwmx_format_header &h, + pwmx_format_misc &m, + const SLAPrint &print, + std::uint32_t layer_count) +{ + std::float_t bottle_weight_g; + std::float_t bottle_volume_ml; + std::float_t bottle_cost; + std::float_t material_density; + auto & cfg = print.full_print_config(); + std::string mnotes = cfg.option("material_notes")->serialize(); + // create a config parser from the material notes + Slic3r::PwmxFormatDynamicConfig mat_cfg; + SLAPrintStatistics stats = print.print_statistics(); + + // sanitize the string config + boost::replace_all(mnotes, "\\n", "\n"); + boost::replace_all(mnotes, "\\r", "\r"); + mat_cfg.load_from_ini_string(mnotes, + ForwardCompatibilitySubstitutionRule::Enable); + + h.layer_height_mm = std::atof(get_cfg_value(cfg, "layer_height")); + m.bottom_layer_height_mm = std::atof( + get_cfg_value(cfg, "initial_layer_height")); + h.exposure_time_s = std::atof(get_cfg_value(cfg, "exposure_time")); + h.bottom_exposure_time_s = std::atof( + get_cfg_value(cfg, "initial_exposure_time")); + h.bottom_layer_count = std::atof(get_cfg_value(cfg, "faded_layers")); + if (layer_count < h.bottom_layer_count) { + h.bottom_layer_count = layer_count; + } + h.res_x = std::atol(get_cfg_value(cfg, "display_pixels_x")); + h.res_y = std::atol(get_cfg_value(cfg, "display_pixels_y")); + bottle_weight_g = std::atof(get_cfg_value(cfg, "bottle_weight")) * 1000.0f; + bottle_volume_ml = std::atof(get_cfg_value(cfg, "bottle_volume")); + bottle_cost = std::atof(get_cfg_value(cfg, "bottle_cost")); + material_density = bottle_weight_g / bottle_volume_ml; + + h.volume_ml = (stats.objects_used_material + stats.support_used_material) / 1000; + h.weight_g = h.volume_ml * material_density; + h.price = (h.volume_ml * bottle_cost) / bottle_volume_ml; + h.price_currency = '$'; + h.antialiasing = 1; + h.per_layer_override = 0; + + // TODO - expose these variables to the UI rather than using material notes + h.delay_before_exposure_s = std::atof( + get_cfg_value(mat_cfg, CFG_DELAY_BEFORE_EXPOSURE, "0.5")); + crop_value(h.delay_before_exposure_s, 0.0f, 1000.0f); + + h.lift_distance_mm = std::atof( + get_cfg_value(mat_cfg, CFG_LIFT_DISTANCE, "8.0")); + crop_value(h.lift_distance_mm, 0.0f, 100.0f); + + if (mat_cfg.has(CFG_BOTTOM_LIFT_DISTANCE)) { + m.bottom_lift_distance_mm = std::atof( + get_cfg_value(mat_cfg, CFG_BOTTOM_LIFT_DISTANCE, "8.0")); + crop_value(h.lift_distance_mm, 0.0f, 100.0f); + } else { + m.bottom_lift_distance_mm = h.lift_distance_mm; + } + + + h.lift_speed_mms = std::atof( + get_cfg_value(mat_cfg, CFG_LIFT_SPEED, "2.0")); + crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f); + + if (mat_cfg.has(CFG_BOTTOM_LIFT_SPEED)) { + m.bottom_lift_speed_mms = std::atof( + get_cfg_value(mat_cfg, CFG_BOTTOM_LIFT_SPEED, "2.0")); + crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f); + } else { + m.bottom_lift_speed_mms = h.lift_speed_mms; + } + + h.retract_speed_mms = std::atof( + get_cfg_value(mat_cfg, CFG_RETRACT_SPEED, "3.0")); + crop_value(h.lift_speed_mms, 0.1f, 20.0f); + + h.print_time_s = (h.bottom_layer_count * h.bottom_exposure_time_s) + + ((layer_count - h.bottom_layer_count) * + h.exposure_time_s) + + (layer_count * h.lift_distance_mm / h.retract_speed_mms) + + (layer_count * h.lift_distance_mm / h.lift_speed_mms) + + (layer_count * h.delay_before_exposure_s); + + + h.payload_size = sizeof(h) - sizeof(h.tag) - sizeof(h.payload_size); + h.pixel_size_um = 50; +} + +} // namespace + +std::unique_ptr PwmxArchive::create_raster() const +{ + sla::Resolution res; + sla::PixelDim pxdim; + std::array mirror; + + double w = m_cfg.display_width.getFloat(); + double h = m_cfg.display_height.getFloat(); + auto pw = size_t(m_cfg.display_pixels_x.getInt()); + auto ph = size_t(m_cfg.display_pixels_y.getInt()); + + mirror[X] = m_cfg.display_mirror_x.getBool(); + mirror[Y] = m_cfg.display_mirror_y.getBool(); + + auto ro = m_cfg.display_orientation.getInt(); + sla::RasterBase::Orientation orientation = + ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait : + sla::RasterBase::roLandscape; + + if (orientation == sla::RasterBase::roPortrait) { + std::swap(w, h); + std::swap(pw, ph); + } + + res = sla::Resolution{pw, ph}; + pxdim = sla::PixelDim{w / pw, h / ph}; + sla::RasterBase::Trafo tr{orientation, mirror}; + + double gamma = m_cfg.gamma_correction.getFloat(); + + return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr); +} + +sla::RasterEncoder PwmxArchive::get_encoder() const +{ + return sla::PWXRasterEncoder{}; +} + +// Endian safe write of little endian 32bit ints +static void pwmx_write_int32(std::ofstream &out, std::uint32_t val) +{ + const char i1 = (val & 0xFF); + const char i2 = (val >> 8) & 0xFF; + const char i3 = (val >> 16) & 0xFF; + const char i4 = (val >> 24) & 0xFF; + + out.write((const char *) &i1, 1); + out.write((const char *) &i2, 1); + out.write((const char *) &i3, 1); + out.write((const char *) &i4, 1); +} +static void pwmx_write_float(std::ofstream &out, std::float_t val) +{ + std::uint32_t *f = (std::uint32_t *) &val; + pwmx_write_int32(out, *f); +} + +static void pwmx_write_intro(std::ofstream &out, pwmx_format_intro &i) +{ + out.write(TAG_INTRO, sizeof(i.tag)); + pwmx_write_int32(out, i.version); + pwmx_write_int32(out, i.area_num); + pwmx_write_int32(out, i.header_data_offset); + pwmx_write_int32(out, i.intro24); + pwmx_write_int32(out, i.preview_data_offset); + pwmx_write_int32(out, i.intro32); + pwmx_write_int32(out, i.layer_data_offset); + pwmx_write_int32(out, i.intro40); + pwmx_write_int32(out, i.image_data_offset); +} + +static void pwmx_write_header(std::ofstream &out, pwmx_format_header &h) +{ + out.write(TAG_HEADER, sizeof(h.tag)); + pwmx_write_int32(out, h.payload_size); + pwmx_write_float(out, h.pixel_size_um); + pwmx_write_float(out, h.layer_height_mm); + pwmx_write_float(out, h.exposure_time_s); + pwmx_write_float(out, h.delay_before_exposure_s); + pwmx_write_float(out, h.bottom_exposure_time_s); + pwmx_write_float(out, h.bottom_layer_count); + pwmx_write_float(out, h.lift_distance_mm); + pwmx_write_float(out, h.lift_speed_mms); + pwmx_write_float(out, h.retract_speed_mms); + pwmx_write_float(out, h.volume_ml); + pwmx_write_int32(out, h.antialiasing); + pwmx_write_int32(out, h.res_x); + pwmx_write_int32(out, h.res_y); + pwmx_write_float(out, h.weight_g); + pwmx_write_float(out, h.price); + pwmx_write_int32(out, h.price_currency); + pwmx_write_int32(out, h.per_layer_override); + pwmx_write_int32(out, h.print_time_s); + pwmx_write_int32(out, h.transition_layer_count); + pwmx_write_int32(out, h.unknown); +} + +static void pwmx_write_preview(std::ofstream &out, pwmx_format_preview &p) +{ + out.write(TAG_PREVIEW, sizeof(p.tag)); + pwmx_write_int32(out, p.payload_size); + pwmx_write_int32(out, p.preview_w); + pwmx_write_int32(out, p.preview_dpi); + pwmx_write_int32(out, p.preview_h); + out.write((const char*) p.pixels, sizeof(p.pixels)); +} + +static void pwmx_write_layers_header(std::ofstream &out, pwmx_format_layers_header &h) +{ + out.write(TAG_LAYERS, sizeof(h.tag)); + pwmx_write_int32(out, h.payload_size); + pwmx_write_int32(out, h.layer_count); +} + +static void pwmx_write_layer(std::ofstream &out, pwmx_format_layer &l) +{ + pwmx_write_int32(out, l.image_offset); + pwmx_write_int32(out, l.image_size); + pwmx_write_float(out, l.lift_distance_mm); + pwmx_write_float(out, l.lift_speed_mms); + pwmx_write_float(out, l.exposure_time_s); + pwmx_write_float(out, l.layer_height_mm); + pwmx_write_float(out, l.layer44); + pwmx_write_float(out, l.layer48); +} + +void PwmxArchive::export_print(const std::string fname, + const SLAPrint & print, + ThumbnailsList & thumbnails, + const std::string &prjname) +{ + std::uint32_t layer_count = m_layers.size(); + + pwmx_format_intro intro = {0}; + pwmx_format_header header = {0}; + pwmx_format_preview preview = {0}; + pwmx_format_layers_header layers_header = {0}; + pwmx_format_misc misc = {0}; + std::vector layer_images; + std::uint32_t image_offset; + + intro.version = 1; + intro.area_num = 4; + intro.header_data_offset = sizeof(intro); + intro.preview_data_offset = sizeof(intro) + sizeof(header); + intro.layer_data_offset = intro.preview_data_offset + sizeof(preview); + intro.image_data_offset = intro.layer_data_offset + + sizeof(layers_header) + + (sizeof(pwmx_format_layer) * layer_count); + + fill_header(header, misc, print, layer_count); + fill_preview(preview, misc, thumbnails); + + try { + // open the file and write the contents + std::ofstream out; + out.open(fname, std::ios::binary | std::ios::out | std::ios::trunc); + pwmx_write_intro(out, intro); + pwmx_write_header(out, header); + pwmx_write_preview(out, preview); + + layers_header.payload_size = intro.image_data_offset - intro.layer_data_offset - + sizeof(layers_header.tag) - sizeof(layers_header.payload_size); + layers_header.layer_count = layer_count; + pwmx_write_layers_header(out, layers_header); + + //layers + layer_images.reserve(layer_count * LAYER_SIZE_ESTIMATE); + image_offset = intro.image_data_offset; + size_t i = 0; + for (const sla::EncodedRaster &rst : m_layers) { + pwmx_format_layer l; + std::memset(&l, 0, sizeof(l)); + l.image_offset = image_offset; + l.image_size = rst.size(); + if (i < header.bottom_layer_count) { + l.exposure_time_s = header.bottom_exposure_time_s; + l.layer_height_mm = misc.bottom_layer_height_mm; + l.lift_distance_mm = misc.bottom_lift_distance_mm; + l.lift_speed_mms = misc.bottom_lift_speed_mms; + } else { + l.exposure_time_s = header.exposure_time_s; + l.layer_height_mm = header.layer_height_mm; + l.lift_distance_mm = header.lift_distance_mm; + l.lift_speed_mms = header.lift_speed_mms; + } + image_offset += l.image_size; + pwmx_write_layer(out, l); + // add the rle encoded layer image into the buffer + const char* img_start = reinterpret_cast(rst.data()); + const char* img_end = img_start + rst.size(); + std::copy(img_start, img_end, std::back_inserter(layer_images)); + i++; + } + const char* img_buffer = reinterpret_cast(layer_images.data()); + out.write(img_buffer, layer_images.size()); + out.close(); + } catch(std::exception& e) { + BOOST_LOG_TRIVIAL(error) << e.what(); + // Rethrow the exception + throw; + } + +} + +} // namespace Slic3r diff --git a/src/libslic3r/Format/pwmx.hpp b/src/libslic3r/Format/pwmx.hpp new file mode 100644 index 000000000..69cec100c --- /dev/null +++ b/src/libslic3r/Format/pwmx.hpp @@ -0,0 +1,36 @@ +#ifndef _SLIC3R_FORMAT_PWMX_HPP_ +#define _SLIC3R_FORMAT_PWMX_HPP_ + +#include + +#include "libslic3r/SLAPrint.hpp" + +namespace Slic3r { + +class PwmxArchive: public SLAArchive { + SLAPrinterConfig m_cfg; + +protected: + std::unique_ptr create_raster() const override; + sla::RasterEncoder get_encoder() const override; + + SLAPrinterConfig & cfg() { return m_cfg; } + const SLAPrinterConfig & cfg() const { return m_cfg; } + +public: + + PwmxArchive() = default; + explicit PwmxArchive(const SLAPrinterConfig &cfg): m_cfg(cfg) {} + explicit PwmxArchive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {} + + void export_print(const std::string fname, + const SLAPrint &print, + ThumbnailsList &thumbnails, + const std::string &projectname = "") override; + bool uses_zipper_export() override {return false;} +}; + + +} // namespace Slic3r::sla + +#endif // _SLIC3R_FORMAT_PWMX_HPP_ diff --git a/src/libslic3r/SLA/RasterBase.cpp b/src/libslic3r/SLA/RasterBase.cpp index 0b6c45eff..fd3f3e062 100644 --- a/src/libslic3r/SLA/RasterBase.cpp +++ b/src/libslic3r/SLA/RasterBase.cpp @@ -16,6 +16,54 @@ const RasterBase::TMirroring RasterBase::MirrorX = {true, false}; const RasterBase::TMirroring RasterBase::MirrorY = {false, true}; const RasterBase::TMirroring RasterBase::MirrorXY = {true, true}; + + +static void pwx_get_pixel_span(const std::uint8_t* ptr, const std::uint8_t* end, + std::uint8_t& pixel, size_t& span_len) +{ + size_t max_len; + + span_len = 0; + pixel = (*ptr) & 0xF0; + // the maximum length of the span depends on the pixel color + max_len = (pixel == 0 || pixel == 0xF0) ? 0xFFF : 0xF; + while (((*ptr) & 0xF0) == pixel && ptr < end && span_len < max_len) { + span_len++; + ptr++; + } +} + +EncodedRaster PWXRasterEncoder::operator()(const void *ptr, size_t w, size_t h, + size_t num_components) +{ + std::vector dst; + size_t span_len; + std::uint8_t pixel; + auto size = w * h * num_components; + dst.reserve(size); + + const std::uint8_t* src = reinterpret_cast(ptr); + const std::uint8_t* src_end = src + size; + while (src < src_end) { + pwx_get_pixel_span(src, src_end, pixel, span_len); + src += span_len; + // fully transparent of fully opaque pixel + if (pixel == 0 || pixel == 0xF0) { + pixel = pixel | (span_len >> 8); + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + pixel = span_len & 0xFF; + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + } + // antialiased pixel + else { + pixel = pixel | span_len; + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + } + } + + return EncodedRaster(std::move(dst), "pwx"); +} + EncodedRaster PNGRasterEncoder::operator()(const void *ptr, size_t w, size_t h, size_t num_components) { diff --git a/src/libslic3r/SLA/RasterBase.hpp b/src/libslic3r/SLA/RasterBase.hpp index 657fc865c..9d22591cc 100644 --- a/src/libslic3r/SLA/RasterBase.hpp +++ b/src/libslic3r/SLA/RasterBase.hpp @@ -97,6 +97,10 @@ public: virtual EncodedRaster encode(RasterEncoder encoder) const = 0; }; +struct PWXRasterEncoder { + EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components); +}; + struct PNGRasterEncoder { EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components); }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 7b78dfea2..23502c44e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -3,6 +3,7 @@ #include "Format/SL1.hpp" #include "Format/SL1_SVG.hpp" +#include "Format/pwmx.hpp" #include "ClipperUtils.hpp" #include "Geometry.hpp" @@ -16,6 +17,8 @@ #include #include +#include + // #define SLAPRINT_DO_BENCHMARK #ifdef SLAPRINT_DO_BENCHMARK @@ -249,6 +252,9 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con m_archiver = std::make_unique(m_printer_config); else if (m_printer_config.sla_archive_format.value == "SL2") m_archiver = std::make_unique(m_printer_config); + else if (m_printer_config.sla_archive_format.value == "pwmx") { + m_archiver = std::make_unique(m_printer_config); + } } struct ModelObjectStatus { @@ -1265,4 +1271,16 @@ void SLAPrint::StatusReporter::operator()(SLAPrint & p, p.set_status(int(std::round(st)), msg, flags); } + +void SLAPrint::write_thumbnail(Zipper& zipper, const ThumbnailData& data) +{ + size_t png_size = 0; + void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); + if (png_data != nullptr) + { + zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size); + mz_free(png_data); + } +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index b2df0c4e9..8d5b54376 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -9,6 +9,7 @@ #include "Point.hpp" #include "MTUtils.hpp" #include "Zipper.hpp" +#include "GCode/ThumbnailData.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" @@ -422,12 +423,16 @@ public: } // Export the print into an archive using the provided zipper. - // TODO: Use an archive writer interface instead of Zipper. - // This is quite limiting as the Zipper is a complete class, not an interface. - // The output can only be a zip archive. virtual void export_print(Zipper &zipper, const SLAPrint &print, - const std::string &projectname = "") = 0; + const std::string &projectname = "") {}; + // Export the print into an archive using the provided filename. + virtual void export_print(const std::string fname, + const SLAPrint &print, + ThumbnailsList &thumbnails, + const std::string &projectname = "") {}; + // By default the exporters use zipper export. Return false to use file export. + virtual bool uses_zipper_export() { return true; } }; /** @@ -533,16 +538,27 @@ public: // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } - - void export_print(Zipper &zipper, const std::string &projectname = "") - { - m_archiver->export_print(zipper, *this, projectname); - } + + void write_thumbnail(Zipper& zipper, const ThumbnailData& data); void export_print(const std::string &fname, const std::string &projectname = "") { - Zipper zipper(fname); - export_print(zipper, projectname); + Slic3r::ThumbnailsList thumbnails; //empty thumbnail list + export_print(fname, thumbnails, projectname); + } + + void export_print(const std::string &fname, Slic3r::ThumbnailsList &thumbnails, const std::string &projectname = "") + { + if (m_archiver->uses_zipper_export()) { + Zipper zipper(fname); + m_archiver->export_print(zipper, *this, projectname); + for (const ThumbnailData& data : thumbnails) + if (data.is_valid()) + write_thumbnail(zipper, data); + zipper.finalize(); + } else { + m_archiver->export_print(fname, *this, thumbnails, projectname); + } } private: diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 5d3d47c20..37e527d64 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -165,17 +165,6 @@ void BackgroundSlicingProcess::process_fff() } } -static void write_thumbnail(Zipper& zipper, const ThumbnailData& data) -{ - size_t png_size = 0; - void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); - if (png_data != nullptr) - { - zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size); - mz_free(png_data); - } -} - void BackgroundSlicingProcess::process_sla() { assert(m_print == m_sla_print); @@ -189,12 +178,7 @@ void BackgroundSlicingProcess::process_sla() ThumbnailsList thumbnails = this->render_thumbnails( ThumbnailsParams{current_print()->full_print_config().option("thumbnails")->values, true, true, true, true}); - Zipper zipper(export_path); - m_sla_print->export_print(zipper); - for (const ThumbnailData& data : thumbnails) - if (data.is_valid()) - write_thumbnail(zipper, data); - zipper.finalize(); + m_sla_print->export_print(export_path, thumbnails); m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str()); } else if (! m_upload_job.empty()) { @@ -739,13 +723,7 @@ void BackgroundSlicingProcess::prepare_upload() ThumbnailsList thumbnails = this->render_thumbnails( ThumbnailsParams{current_print()->full_print_config().option("thumbnails")->values, true, true, true, true}); - // true, false, true, true); // renders also supports and pad - Zipper zipper{source_path.string()}; - m_sla_print->export_print(zipper, m_upload_job.upload_data.upload_path.string()); - for (const ThumbnailData& data : thumbnails) - if (data.is_valid()) - write_thumbnail(zipper, data); - zipper.finalize(); + m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.string()); } m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b55ba0d75..b914d8db4 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -496,7 +496,7 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = { /* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } }, - /* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } }, + /* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv, ".pwmx"sv } }, }; // This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms. From df0751716c2cc031cc8b3ffabd272ac55c1b0b6f Mon Sep 17 00:00:00 2001 From: ole00 Date: Sat, 12 Feb 2022 01:13:58 +0000 Subject: [PATCH 10/27] Added resources and settings for Anycubic Photon Mono X SLA printer --- resources/profiles/Anycubic.ini | 100 ++++++++++++++++++ .../Anycubic/PHOTON MONO X_thumbnail.png | Bin 0 -> 45953 bytes 2 files changed, 100 insertions(+) create mode 100644 resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png diff --git a/resources/profiles/Anycubic.ini b/resources/profiles/Anycubic.ini index 053aecbd5..a67ba0962 100644 --- a/resources/profiles/Anycubic.ini +++ b/resources/profiles/Anycubic.ini @@ -64,6 +64,13 @@ technology = FFF family = PREDATOR default_materials = Generic PLA @PREDATOR; Generic PETG @PREDATOR; Generic ABS @PREDATOR +[printer_model:PHOTON MONO X] +name = Photon Mono X +variants = default +technology = SLA +family = PHOTON MONO +default_materials = Generic Blue Resin MONO @0.05 + # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -1898,3 +1905,96 @@ default_print_profile = 0.24mm 0.8 nozzle DETAILED QUALITY @PREDATOR ######################################### ########## end printer presets ########## ######################################### + +######################################### +########## SLA printer presets ########## +######################################### + + +[sla_print:*common print ANYCUBIC SLA*] +compatible_printers_condition = family=="PHOTON MONO" +layer_height = 0.05 +output_filename_format = [input_filename_base].pwmx +pad_edge_radius = 0.5 +pad_enable = 0 +pad_max_merge_distance = 50 +pad_wall_height = 0 +pad_wall_thickness = 1 +pad_wall_slope = 45 +faded_layers = 8 +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_critical_angle = 45 +support_density_at_45 = 250 +support_density_at_horizontal = 500 +support_head_front_diameter = 0.4 +support_head_penetration = 0.4 +support_head_width = 3 +support_max_bridge_length = 10 +support_minimal_z = 0 +support_object_elevation = 5 +support_pillar_diameter = 1 +support_pillar_connection_mode = zigzag +support_pillar_widening_factor = 0 +supports_enable = 1 +support_small_pillar_diameter_percent = 60% + +[sla_print:0.05 ANYCUBIC SLA] +inherits = *common print ANYCUBIC SLA* +layer_height = 0.05 + + +########### Materials + +[sla_material:*common ANYCUBIC SLA*] +compatible_printers_condition = family=="PHOTON MONO" +compatible_prints_condition = layer_height == 0.05 +exposure_time = 7 +initial_exposure_time = 40 +initial_layer_height = 0.05 +material_correction = 1,1,1 +material_notes = LIFT_DISTANCE=8.0\nLIFT_SPEED=2.5\nRETRACT_SPEED=3.0\nBOTTOM_LIFT_SPEED=2.0\nBOTTOM_LIFT_DISTANCE=9.0\nDELAY_BEFORE_EXPOSURE=0.5 + +[sla_material:*common 0.05 ANYCUBIC SLA*] +inherits = *common ANYCUBIC SLA* + +[sla_material:Generic Blue Resin MONO @0.05] +inherits = *common 0.05 ANYCUBIC SLA* +exposure_time = 2.5 +initial_exposure_time = 40 +material_type = Tough +material_vendor = Generic +material_colour = #6080EC + +########## Printers + +[printer:Anycubic Photon Mono X] +printer_technology = SLA +printer_model = PHOTON MONO X +printer_variant = default +default_sla_material_profile = Generic Blue Resin MONO @0.05 +default_sla_print_profile = 0.05 ANYCUBIC SLA +thumbnails = 224x168 +sla_archive_format = pwmx +bed_shape = 1.48x1.02,193.48x1.02,193.48x121.02,1.48x121.02 +display_height = 120 +display_orientation = landscape +display_mirror_x = 1 +display_mirror_y = 0 +display_pixels_x = 3840 +display_pixels_y = 2400 +display_width = 192 +max_print_height = 245 +elefant_foot_compensation = 0.2 +elefant_foot_min_width = 0.2 +min_exposure_time = 1 +max_exposure_time = 120 +min_initial_exposure_time = 1 +max_initial_exposure_time = 300 +printer_correction = 1,1,1 +gamma_correction = 1 +area_fill = 45 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.'\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTONMONOX\n + + diff --git a/resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png b/resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..70ad47b63defdbd22c913d211d284a1bed729860 GIT binary patch literal 45953 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

?9hL)5+9SL}$(eIdYR*>(Nn1RXY00 z_y?`E?Af!*=GK;9okh|fAvy@noZ}L$pR6G6jMJbHt59MnO^?Eq7+qpai7pC^DKJI+ zDZ@{Xvg}iq;rYf;7KVOV(u+TZp^T3g1-%Afzw|IWdyZ(#3%gZ#&z|K~h>&lh;wH+(bC{MPT{ zS(>Rx;U=5>KfkshS%|mm;E!ehM#=#5AvE{{x>WwFY}3y{V6~G(wq6#Z~IRE z(R03w5B`t$bIZ@af=l-A;|rhrEdS)2zJa>(RvMrD>rb<=xWxP4`)+>bm9ONVJokHe z_IEs&|MBj3@Y-MeIhIyd(zb8K@pJ$B7XJO4-pG4@|6TmiAAW$Jc*QFj42Rjuq~^Cx z=XO(7#}BpRRT(vU99{p$zzS&L&(>cyWEw@>6(2tK@cCPz^Of3(OSzPYAfXsjS(`U* z*HM2X=AP~2A;-)gSN?ek0SS6@Y3oezf%5gFQk4A?0S+8IM1Of7Tk9tQp)3bHc;6j- z@ZG=3bXw8Wj%qUE!|!=J|LP65a_QAK@cl3QC9eP9{vm(#&i~B!{L>%h;rs97@dqE^ z|9JlQ@h9)Too9X9^ZB+Hyp$`h`#b#P>u=>l?|wU58z*`G5B~(c;gDC|{5_mFeuT2W z&=n_h!gM<2H-Gm%-2bJ!x%!Grx%;lWSkkb#xX7)){;T}6AN>(-`jMA%{S9Bot^e)a zyyJI%hf^mvc;#zf&(m(ak!StAujAo|9-ve(7!G*rfBX;p)KC8$FTCj{p7!Z^zlT-EW(Qr#|iJ{FmQ)8~^mCAL1=-~KfV!vWv_W50lH8mzUPI&qu_?z)5F z;ws`iS6aK8UVj+!N}<2Biq@LZ6sDtf8Z46uEG;d2PIOa&cp-ADG=sqcx4!w+yy)hi z=i`6+N4)XX|2NWK@;)lzD*;sfgU~MOrvJPytBA zb9XFEP$GpA=oRG<;Jz>2E9M*u!za2z$H-gPTK|X zryuPl1adJ*t&M-o7?d(-rO{|_Z6-C({MP64vRD5ad-h+3wGAlY#;1Q1|ME4z#^TCe z#5o3w%RJ}#H}Te6Ue4OlNBGb?-^S-Y`4Rr{cfSx@JF0q0caqm5M@ru{Jg%|$FPcR*iXP`YWrr^Yh6HKNRH~r|3 zBO;7}Q)_Gd%rD%+AO67~@VeK$iof~GkMjdB_&$E|mRmr>#`;O_yz7g+@jv}1-uQ+$ zP*-D4ojl2_|DV_Mw%cyy^}l=zfB6?5;YBySh+lm5EuA!QVPTQqzV+AnzVCf5Z+`1- zjMq=_(?9hueaexYV69sGU8~mHTg3-7Db-7c@G7OYfLH9>x9?fkTyxE!wC)tx`IXa$!$hH{OsT z;tMTwmUj`9ptJ;W!aS){?G~Ajf{_q56tJ+k!hu8AQcb6fH`i(E8dDTpas7=nP0i-1 zlkDApkb~EK9pkMHzV{_R$JajnncVrAPw<7m`8Y58rC;HSuX!4y%~M?a)TeXZ)1JX- zYlD3U4)W~hy@=6xlP}+QFW+<1kMq1A`Y}dZ8$9EizmqGj`Wn_w9Os8#`qTWJ;KStqR5z7~}J5 zi%{7HE0P)jKIjxmX>FY?aFRI9nFeigDu|7q*61o{2&xb(s+8QUNGl3sP)cJxaU$t8 zt7w-&+w%9%K%*$dxuEf^0=+fZImaR_Skj3SuaTND+WbhbXi%kJY(=!z!4BHBtEX0M zw|`FZj{bd|Q%dUslooN4Fm`$Hn8~aq+l#Ts$rw7mtg_#pB{}@wj+gJpO-k{C}%O`IChc3wZzl002ovPDHLk FV1nTQC-eXS literal 0 HcmV?d00001 From 69019ae4bb16473a33ad681c2a8cb57887e5c830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 14 Feb 2022 08:20:57 +0100 Subject: [PATCH 11/27] Added a missing include (GCC11.1 without PCH). --- src/slic3r/GUI/MeshUtils.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 11ebf9386..cc961ee8f 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -3,6 +3,7 @@ #include "libslic3r/Point.hpp" #include "libslic3r/Geometry.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/SLA/IndexedMesh.hpp" #include "admesh/stl.h" From 41e31c31b60280c89f03bc3f8348555285f9fe99 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Mon, 14 Feb 2022 09:33:40 +0100 Subject: [PATCH 12/27] Updated Anycubic Photon structure. --- resources/profiles/Anycubic.ini | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/resources/profiles/Anycubic.ini b/resources/profiles/Anycubic.ini index a67ba0962..821d87462 100644 --- a/resources/profiles/Anycubic.ini +++ b/resources/profiles/Anycubic.ini @@ -69,7 +69,7 @@ name = Photon Mono X variants = default technology = SLA family = PHOTON MONO -default_materials = Generic Blue Resin MONO @0.05 +default_materials = Generic Blue Resin @MONO 0.05 # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -1940,15 +1940,14 @@ support_pillar_widening_factor = 0 supports_enable = 1 support_small_pillar_diameter_percent = 60% -[sla_print:0.05 ANYCUBIC SLA] +[sla_print:0.05 Normal @ANYCUBIC] inherits = *common print ANYCUBIC SLA* layer_height = 0.05 - ########### Materials [sla_material:*common ANYCUBIC SLA*] -compatible_printers_condition = family=="PHOTON MONO" +compatible_printers_condition = printer_notes=~/.*PHOTONMONOX.*/ compatible_prints_condition = layer_height == 0.05 exposure_time = 7 initial_exposure_time = 40 @@ -1959,13 +1958,14 @@ material_notes = LIFT_DISTANCE=8.0\nLIFT_SPEED=2.5\nRETRACT_SPEED=3.0\nBOTTOM_LI [sla_material:*common 0.05 ANYCUBIC SLA*] inherits = *common ANYCUBIC SLA* -[sla_material:Generic Blue Resin MONO @0.05] +[sla_material:Generic Blue Resin @MONO 0.05] inherits = *common 0.05 ANYCUBIC SLA* exposure_time = 2.5 initial_exposure_time = 40 material_type = Tough material_vendor = Generic material_colour = #6080EC +compatible_printers_condition = printer_notes=~/.*PHOTONMONOX.*/ ########## Printers @@ -1973,8 +1973,8 @@ material_colour = #6080EC printer_technology = SLA printer_model = PHOTON MONO X printer_variant = default -default_sla_material_profile = Generic Blue Resin MONO @0.05 -default_sla_print_profile = 0.05 ANYCUBIC SLA +default_sla_material_profile = Generic Blue Resin @MONO 0.05 +default_sla_print_profile = 0.05 Normal @ANYCUBIC thumbnails = 224x168 sla_archive_format = pwmx bed_shape = 1.48x1.02,193.48x1.02,193.48x121.02,1.48x121.02 @@ -1996,5 +1996,3 @@ printer_correction = 1,1,1 gamma_correction = 1 area_fill = 45 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.'\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTONMONOX\n - - From 05087540334682dfe657f039fe7d94a5cc47e6cb Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 14 Feb 2022 09:53:59 +0100 Subject: [PATCH 13/27] SLA SVG export: Using string_view literals to avoid unnecessary std::string allocations and faster string additions (length of a string_view literal is known without having to iterate to the trailing NULL). --- src/libslic3r/Format/SL1_SVG.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Format/SL1_SVG.cpp b/src/libslic3r/Format/SL1_SVG.cpp index 0ea230611..a7a8c9ed6 100644 --- a/src/libslic3r/Format/SL1_SVG.cpp +++ b/src/libslic3r/Format/SL1_SVG.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +using namespace std::literals; namespace Slic3r { @@ -77,20 +79,23 @@ void append_svg(std::string &buf, const Polygon &poly) char intbuf[coord_t_bufsize]; - buf += std::string(" data; - constexpr const char finish[] = "\n"; + constexpr auto finish = "\n"sv; data.reserve(m_svg.size() + std::size(finish)); std::copy(m_svg.begin(), m_svg.end(), std::back_inserter(data)); - std::copy(finish, finish + std::size(finish) - 1, std::back_inserter(data)); + std::copy(finish.begin(), finish.end() - 1, std::back_inserter(data)); return sla::EncodedRaster{std::move(data), "svg"}; } From 5e78203241e343610e072f54e0f2498723087c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 14 Feb 2022 10:47:39 +0100 Subject: [PATCH 14/27] Added missing includes (GCC11.1 without PCH). --- src/libslic3r/Format/pwmx.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libslic3r/Format/pwmx.cpp b/src/libslic3r/Format/pwmx.cpp index 99785b8d0..3be3c3d57 100644 --- a/src/libslic3r/Format/pwmx.cpp +++ b/src/libslic3r/Format/pwmx.cpp @@ -5,6 +5,9 @@ #include #include +#include +#include + #define TAG_INTRO "ANYCUBIC\0\0\0\0" #define TAG_HEADER "HEADER\0\0\0\0\0\0" From 5fcb618f96064d8dbd5803dc3d773b37b81cde49 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 14 Feb 2022 14:23:07 +0100 Subject: [PATCH 15/27] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Fixed bug in rendering gizmo rotate --- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 362e25309..dca578bd7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -134,15 +134,14 @@ void GLGizmoRotate::on_render() if (shader != nullptr) { shader->start_using(); - const float radius = Offset + m_parent.get_selection().get_bounding_box().radius(); - const bool radius_changed = std::abs(m_old_radius - radius) > EPSILON; - m_old_radius = radius; + const bool radius_changed = std::abs(m_old_radius - m_radius) > EPSILON; + m_old_radius = m_radius; ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color); render_circle(color, radius_changed); if (m_hover_id != -1) { - const bool hover_radius_changed = std::abs(m_old_hover_radius - radius) > EPSILON; - m_old_hover_radius = radius; + const bool hover_radius_changed = std::abs(m_old_hover_radius - m_radius) > EPSILON; + m_old_hover_radius = m_radius; render_scale(color, hover_radius_changed); render_snap_radii(color, hover_radius_changed); From b6fe41d5abdb78149ae15a7e87c3d60625f0f47e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 14 Feb 2022 13:27:06 +0100 Subject: [PATCH 16/27] Fixes for pwmx format PR --- src/libslic3r/Format/SL1.cpp | 36 +++++++- src/libslic3r/Format/SL1.hpp | 7 +- src/libslic3r/Format/pwmx.cpp | 154 ++++++++++++++++++++----------- src/libslic3r/Format/pwmx.hpp | 11 +-- src/libslic3r/SLA/RasterBase.cpp | 48 ---------- src/libslic3r/SLA/RasterBase.hpp | 4 - src/libslic3r/SLAPrint.cpp | 14 --- src/libslic3r/SLAPrint.hpp | 33 ++----- 8 files changed, 154 insertions(+), 153 deletions(-) diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index 6f1e95528..df10ce046 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -20,11 +20,14 @@ #include "libslic3r/miniz_extension.hpp" #include "libslic3r/PNGReadWrite.hpp" #include "libslic3r/LocalesUtils.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" #include #include #include +#include + namespace marchsq { template<> struct _RasterTraits { @@ -482,10 +485,31 @@ sla::RasterEncoder SL1Archive::get_encoder() const return sla::PNGRasterEncoder{}; } -void SL1Archive::export_print(Zipper& zipper, - const SLAPrint &print, - const std::string &prjname) +static void write_thumbnail(Zipper &zipper, const ThumbnailData &data) { + size_t png_size = 0; + + void *png_data = tdefl_write_image_to_png_file_in_memory_ex( + (const void *) data.pixels.data(), data.width, data.height, 4, + &png_size, MZ_DEFAULT_LEVEL, 1); + + if (png_data != nullptr) { + zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + + "x" + std::to_string(data.height) + ".png", + static_cast(png_data), + png_size); + + mz_free(png_data); + } +} + +void SL1Archive::export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &prjname) +{ + Zipper zipper{fname}; + std::string project = prjname.empty() ? boost::filesystem::path(zipper.get_filename()).stem().string() : @@ -512,6 +536,12 @@ void SL1Archive::export_print(Zipper& zipper, zipper.add_entry(imgname.c_str(), rst.data(), rst.size()); } + + for (const ThumbnailData& data : thumbnails) + if (data.is_valid()) + write_thumbnail(zipper, data); + + zipper.finalize(); } catch(std::exception& e) { BOOST_LOG_TRIVIAL(error) << e.what(); // Rethrow the exception diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp index e6c0ff089..874786eb9 100644 --- a/src/libslic3r/Format/SL1.hpp +++ b/src/libslic3r/Format/SL1.hpp @@ -23,8 +23,11 @@ public: SL1Archive() = default; explicit SL1Archive(const SLAPrinterConfig &cfg): m_cfg(cfg) {} explicit SL1Archive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {} - - void export_print(Zipper &zipper, const SLAPrint &print, const std::string &projectname = "") override; + + void export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &projectname = "") override; }; ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrintConfig &out); diff --git a/src/libslic3r/Format/pwmx.cpp b/src/libslic3r/Format/pwmx.cpp index 3be3c3d57..5b420a49e 100644 --- a/src/libslic3r/Format/pwmx.cpp +++ b/src/libslic3r/Format/pwmx.cpp @@ -1,5 +1,6 @@ #include "pwmx.hpp" #include "GCode/ThumbnailData.hpp" +#include "SLA/RasterBase.hpp" #include #include @@ -27,9 +28,59 @@ #define LAYER_SIZE_ESTIMATE (32 * 1024) - namespace Slic3r { +static void pwx_get_pixel_span(const std::uint8_t* ptr, const std::uint8_t* end, + std::uint8_t& pixel, size_t& span_len) +{ + size_t max_len; + + span_len = 0; + pixel = (*ptr) & 0xF0; + // the maximum length of the span depends on the pixel color + max_len = (pixel == 0 || pixel == 0xF0) ? 0xFFF : 0xF; + while (ptr < end && span_len < max_len && ((*ptr) & 0xF0) == pixel) { + span_len++; + ptr++; + } +} + +struct PWXRasterEncoder +{ + sla::EncodedRaster operator()(const void *ptr, + size_t w, + size_t h, + size_t num_components) + { + std::vector dst; + size_t span_len; + std::uint8_t pixel; + auto size = w * h * num_components; + dst.reserve(size); + + const std::uint8_t *src = reinterpret_cast(ptr); + const std::uint8_t *src_end = src + size; + while (src < src_end) { + pwx_get_pixel_span(src, src_end, pixel, span_len); + src += span_len; + // fully transparent of fully opaque pixel + if (pixel == 0 || pixel == 0xF0) { + pixel = pixel | (span_len >> 8); + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + pixel = span_len & 0xFF; + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + } + // antialiased pixel + else { + pixel = pixel | span_len; + std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); + } + } + + return sla::EncodedRaster(std::move(dst), "pwx"); + } +}; + using ConfMap = std::map; typedef struct pwmx_format_intro @@ -137,24 +188,28 @@ private: namespace { -const char *get_cfg_value(const DynamicConfig &cfg, - const std::string & key, - const std::string & def = "0") +std::float_t get_cfg_value_f(const DynamicConfig &cfg, + const std::string &key, + const std::float_t &def = 0.f) { - std::string ret; - if (cfg.has(key)) { - auto opt = cfg.option(key); - if (opt) { - ret = opt->serialize(); - } else { - return def.c_str(); - } - } else { - return def.c_str(); + if (auto opt = cfg.option(key)) + return opt->getFloat(); } - return ret.c_str(); + return def; +} + +int get_cfg_value_i(const DynamicConfig &cfg, + const std::string &key, + const int &def = 0) +{ + if (cfg.has(key)) { + if (auto opt = cfg.option(key)) + return opt->getInt(); + } + + return def; } template void crop_value(T &val, T val_min, T val_max) @@ -167,8 +222,8 @@ template void crop_value(T &val, T val_min, T val_max) } void fill_preview(pwmx_format_preview &p, - pwmx_format_misc &m, - ThumbnailsList &thumbnails) + pwmx_format_misc &/*m*/, + const ThumbnailsList &thumbnails) { p.preview_w = PREV_W; @@ -216,6 +271,8 @@ void fill_header(pwmx_format_header &h, const SLAPrint &print, std::uint32_t layer_count) { + CNumericLocalesSetter locales_setter; + std::float_t bottle_weight_g; std::float_t bottle_volume_ml; std::float_t bottle_cost; @@ -232,21 +289,19 @@ void fill_header(pwmx_format_header &h, mat_cfg.load_from_ini_string(mnotes, ForwardCompatibilitySubstitutionRule::Enable); - h.layer_height_mm = std::atof(get_cfg_value(cfg, "layer_height")); - m.bottom_layer_height_mm = std::atof( - get_cfg_value(cfg, "initial_layer_height")); - h.exposure_time_s = std::atof(get_cfg_value(cfg, "exposure_time")); - h.bottom_exposure_time_s = std::atof( - get_cfg_value(cfg, "initial_exposure_time")); - h.bottom_layer_count = std::atof(get_cfg_value(cfg, "faded_layers")); + h.layer_height_mm = get_cfg_value_f(cfg, "layer_height"); + m.bottom_layer_height_mm = get_cfg_value_f(cfg, "initial_layer_height"); + h.exposure_time_s = get_cfg_value_f(cfg, "exposure_time"); + h.bottom_exposure_time_s = get_cfg_value_f(cfg, "initial_exposure_time"); + h.bottom_layer_count = get_cfg_value_i(cfg, "faded_layers"); if (layer_count < h.bottom_layer_count) { h.bottom_layer_count = layer_count; } - h.res_x = std::atol(get_cfg_value(cfg, "display_pixels_x")); - h.res_y = std::atol(get_cfg_value(cfg, "display_pixels_y")); - bottle_weight_g = std::atof(get_cfg_value(cfg, "bottle_weight")) * 1000.0f; - bottle_volume_ml = std::atof(get_cfg_value(cfg, "bottle_volume")); - bottle_cost = std::atof(get_cfg_value(cfg, "bottle_cost")); + h.res_x = get_cfg_value_i(cfg, "display_pixels_x"); + h.res_y = get_cfg_value_i(cfg, "display_pixels_y"); + bottle_weight_g = get_cfg_value_f(cfg, "bottle_weight") * 1000.0f; + bottle_volume_ml = get_cfg_value_f(cfg, "bottle_volume"); + bottle_cost = get_cfg_value_f(cfg, "bottle_cost"); material_density = bottle_weight_g / bottle_volume_ml; h.volume_ml = (stats.objects_used_material + stats.support_used_material) / 1000; @@ -257,37 +312,32 @@ void fill_header(pwmx_format_header &h, h.per_layer_override = 0; // TODO - expose these variables to the UI rather than using material notes - h.delay_before_exposure_s = std::atof( - get_cfg_value(mat_cfg, CFG_DELAY_BEFORE_EXPOSURE, "0.5")); + h.delay_before_exposure_s = get_cfg_value_f(mat_cfg, CFG_DELAY_BEFORE_EXPOSURE, 0.5f); crop_value(h.delay_before_exposure_s, 0.0f, 1000.0f); - h.lift_distance_mm = std::atof( - get_cfg_value(mat_cfg, CFG_LIFT_DISTANCE, "8.0")); + h.lift_distance_mm = get_cfg_value_f(mat_cfg, CFG_LIFT_DISTANCE, 8.0f); crop_value(h.lift_distance_mm, 0.0f, 100.0f); if (mat_cfg.has(CFG_BOTTOM_LIFT_DISTANCE)) { - m.bottom_lift_distance_mm = std::atof( - get_cfg_value(mat_cfg, CFG_BOTTOM_LIFT_DISTANCE, "8.0")); + m.bottom_lift_distance_mm = get_cfg_value_f(mat_cfg, + CFG_BOTTOM_LIFT_DISTANCE, + 8.0f); crop_value(h.lift_distance_mm, 0.0f, 100.0f); } else { m.bottom_lift_distance_mm = h.lift_distance_mm; } - - h.lift_speed_mms = std::atof( - get_cfg_value(mat_cfg, CFG_LIFT_SPEED, "2.0")); + h.lift_speed_mms = get_cfg_value_f(mat_cfg, CFG_LIFT_SPEED, 2.0f); crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f); if (mat_cfg.has(CFG_BOTTOM_LIFT_SPEED)) { - m.bottom_lift_speed_mms = std::atof( - get_cfg_value(mat_cfg, CFG_BOTTOM_LIFT_SPEED, "2.0")); + m.bottom_lift_speed_mms = get_cfg_value_f(mat_cfg, CFG_BOTTOM_LIFT_SPEED, 2.0f); crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f); } else { m.bottom_lift_speed_mms = h.lift_speed_mms; } - h.retract_speed_mms = std::atof( - get_cfg_value(mat_cfg, CFG_RETRACT_SPEED, "3.0")); + h.retract_speed_mms = get_cfg_value_f(mat_cfg, CFG_RETRACT_SPEED, 3.0f); crop_value(h.lift_speed_mms, 0.1f, 20.0f); h.print_time_s = (h.bottom_layer_count * h.bottom_exposure_time_s) + @@ -339,7 +389,7 @@ std::unique_ptr PwmxArchive::create_raster() const sla::RasterEncoder PwmxArchive::get_encoder() const { - return sla::PWXRasterEncoder{}; + return PWXRasterEncoder{}; } // Endian safe write of little endian 32bit ints @@ -430,18 +480,18 @@ static void pwmx_write_layer(std::ofstream &out, pwmx_format_layer &l) pwmx_write_float(out, l.layer48); } -void PwmxArchive::export_print(const std::string fname, - const SLAPrint & print, - ThumbnailsList & thumbnails, - const std::string &prjname) +void PwmxArchive::export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &/*projectname*/) { std::uint32_t layer_count = m_layers.size(); - pwmx_format_intro intro = {0}; - pwmx_format_header header = {0}; - pwmx_format_preview preview = {0}; - pwmx_format_layers_header layers_header = {0}; - pwmx_format_misc misc = {0}; + pwmx_format_intro intro = {}; + pwmx_format_header header = {}; + pwmx_format_preview preview = {}; + pwmx_format_layers_header layers_header = {}; + pwmx_format_misc misc = {}; std::vector layer_images; std::uint32_t image_offset; diff --git a/src/libslic3r/Format/pwmx.hpp b/src/libslic3r/Format/pwmx.hpp index 69cec100c..d1179c014 100644 --- a/src/libslic3r/Format/pwmx.hpp +++ b/src/libslic3r/Format/pwmx.hpp @@ -22,12 +22,11 @@ public: PwmxArchive() = default; explicit PwmxArchive(const SLAPrinterConfig &cfg): m_cfg(cfg) {} explicit PwmxArchive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {} - - void export_print(const std::string fname, - const SLAPrint &print, - ThumbnailsList &thumbnails, - const std::string &projectname = "") override; - bool uses_zipper_export() override {return false;} + + void export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &projectname = "") override; }; diff --git a/src/libslic3r/SLA/RasterBase.cpp b/src/libslic3r/SLA/RasterBase.cpp index fd3f3e062..0b6c45eff 100644 --- a/src/libslic3r/SLA/RasterBase.cpp +++ b/src/libslic3r/SLA/RasterBase.cpp @@ -16,54 +16,6 @@ const RasterBase::TMirroring RasterBase::MirrorX = {true, false}; const RasterBase::TMirroring RasterBase::MirrorY = {false, true}; const RasterBase::TMirroring RasterBase::MirrorXY = {true, true}; - - -static void pwx_get_pixel_span(const std::uint8_t* ptr, const std::uint8_t* end, - std::uint8_t& pixel, size_t& span_len) -{ - size_t max_len; - - span_len = 0; - pixel = (*ptr) & 0xF0; - // the maximum length of the span depends on the pixel color - max_len = (pixel == 0 || pixel == 0xF0) ? 0xFFF : 0xF; - while (((*ptr) & 0xF0) == pixel && ptr < end && span_len < max_len) { - span_len++; - ptr++; - } -} - -EncodedRaster PWXRasterEncoder::operator()(const void *ptr, size_t w, size_t h, - size_t num_components) -{ - std::vector dst; - size_t span_len; - std::uint8_t pixel; - auto size = w * h * num_components; - dst.reserve(size); - - const std::uint8_t* src = reinterpret_cast(ptr); - const std::uint8_t* src_end = src + size; - while (src < src_end) { - pwx_get_pixel_span(src, src_end, pixel, span_len); - src += span_len; - // fully transparent of fully opaque pixel - if (pixel == 0 || pixel == 0xF0) { - pixel = pixel | (span_len >> 8); - std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); - pixel = span_len & 0xFF; - std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); - } - // antialiased pixel - else { - pixel = pixel | span_len; - std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst)); - } - } - - return EncodedRaster(std::move(dst), "pwx"); -} - EncodedRaster PNGRasterEncoder::operator()(const void *ptr, size_t w, size_t h, size_t num_components) { diff --git a/src/libslic3r/SLA/RasterBase.hpp b/src/libslic3r/SLA/RasterBase.hpp index 9d22591cc..657fc865c 100644 --- a/src/libslic3r/SLA/RasterBase.hpp +++ b/src/libslic3r/SLA/RasterBase.hpp @@ -97,10 +97,6 @@ public: virtual EncodedRaster encode(RasterEncoder encoder) const = 0; }; -struct PWXRasterEncoder { - EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components); -}; - struct PNGRasterEncoder { EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components); }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 23502c44e..2622b6a23 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -17,8 +17,6 @@ #include #include -#include - // #define SLAPRINT_DO_BENCHMARK #ifdef SLAPRINT_DO_BENCHMARK @@ -1271,16 +1269,4 @@ void SLAPrint::StatusReporter::operator()(SLAPrint & p, p.set_status(int(std::round(st)), msg, flags); } - -void SLAPrint::write_thumbnail(Zipper& zipper, const ThumbnailData& data) -{ - size_t png_size = 0; - void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); - if (png_data != nullptr) - { - zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size); - mz_free(png_data); - } -} - } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 8d5b54376..2d49139a4 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -422,17 +422,11 @@ public: execution::max_concurrency(ep)); } - // Export the print into an archive using the provided zipper. - virtual void export_print(Zipper &zipper, - const SLAPrint &print, - const std::string &projectname = "") {}; // Export the print into an archive using the provided filename. - virtual void export_print(const std::string fname, - const SLAPrint &print, - ThumbnailsList &thumbnails, - const std::string &projectname = "") {}; - // By default the exporters use zipper export. Return false to use file export. - virtual bool uses_zipper_export() { return true; } + virtual void export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &projectname = "") = 0; }; /** @@ -538,27 +532,18 @@ public: // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } - - void write_thumbnail(Zipper& zipper, const ThumbnailData& data); void export_print(const std::string &fname, const std::string &projectname = "") { - Slic3r::ThumbnailsList thumbnails; //empty thumbnail list + ThumbnailsList thumbnails; //empty thumbnail list export_print(fname, thumbnails, projectname); } - void export_print(const std::string &fname, Slic3r::ThumbnailsList &thumbnails, const std::string &projectname = "") + void export_print(const std::string &fname, + const ThumbnailsList &thumbnails, + const std::string &projectname = "") { - if (m_archiver->uses_zipper_export()) { - Zipper zipper(fname); - m_archiver->export_print(zipper, *this, projectname); - for (const ThumbnailData& data : thumbnails) - if (data.is_valid()) - write_thumbnail(zipper, data); - zipper.finalize(); - } else { - m_archiver->export_print(fname, *this, thumbnails, projectname); - } + m_archiver->export_print(fname, *this, thumbnails, projectname); } private: From 3633112148e5da0c192b4ad0f099af171beaac3c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Feb 2022 10:17:57 +0100 Subject: [PATCH 17/27] Follow-up of 7150e0adda2673797b624e314782a81ca8279bb7 - Fix in clamping max bounding box to avoid z-fighting in gcode preview --- src/slic3r/GUI/GLCanvas3D.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index edd62ce0a..1df16e6b7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5025,9 +5025,9 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be // clamp max bb size with respect to bed bb size if (!m_picking_enabled) { - static const double max_scale_factor = 1.5; + static const double max_scale_factor = 2.0; const Vec3d bb_size = bb.size(); - const Vec3d bed_bb_size = bed_bb.size(); + const Vec3d bed_bb_size = m_bed.build_volume().bounding_volume().size(); if (bb_size.x() > max_scale_factor * bed_bb_size.x() || bb_size.y() > max_scale_factor * bed_bb_size.y() || bb_size.z() > max_scale_factor * bed_bb_size.z()) { @@ -5037,6 +5037,9 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be } } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + std::cout << to_string(bb.size()) << "\n"; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ return bb; } From 6c397e291cc199d4da8d9ffc23dff1384584049d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Feb 2022 10:18:47 +0100 Subject: [PATCH 18/27] Removed debug code committed by mistake --- src/slic3r/GUI/GLCanvas3D.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1df16e6b7..865190e46 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5037,9 +5037,6 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be } } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << to_string(bb.size()) << "\n"; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ return bb; } From 66f60de5560ba0bc9577c0ed85565e03f865b7ac Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 17 Feb 2022 12:48:17 +0100 Subject: [PATCH 19/27] SLAArchive framework refactor --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Format/SL1.hpp | 4 +- src/libslic3r/Format/SLAArchive.cpp | 74 ++++++++++++++++++++ src/libslic3r/Format/SLAArchive.hpp | 64 +++++++++++++++++ src/libslic3r/Format/pwmx.cpp | 6 +- src/libslic3r/Format/pwmx.hpp | 4 +- src/libslic3r/SLAPrint.cpp | 11 +-- src/libslic3r/SLAPrint.hpp | 40 +---------- src/slic3r/GUI/Jobs/SLAImportJob.cpp | 1 + tests/libnest2d/CMakeLists.txt | 4 +- tests/sla_print/CMakeLists.txt | 3 +- tests/sla_print/sla_archive_export_tests.cpp | 37 ++++++++++ tests/slic3rutils/CMakeLists.txt | 4 +- 13 files changed, 199 insertions(+), 55 deletions(-) create mode 100644 src/libslic3r/Format/SLAArchive.cpp create mode 100644 src/libslic3r/Format/SLAArchive.hpp create mode 100644 tests/sla_print/sla_archive_export_tests.cpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index ea663f2e1..046aba763 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -94,6 +94,8 @@ set(SLIC3R_SOURCES Format/objparser.hpp Format/STL.cpp Format/STL.hpp + Format/SLAArchive.hpp + Format/SLAArchive.cpp Format/SL1.hpp Format/SL1.cpp Format/SL1_SVG.hpp diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp index 874786eb9..8ed9dc329 100644 --- a/src/libslic3r/Format/SL1.hpp +++ b/src/libslic3r/Format/SL1.hpp @@ -3,8 +3,10 @@ #include +#include "SLAArchive.hpp" + #include "libslic3r/Zipper.hpp" -#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/Format/SLAArchive.cpp b/src/libslic3r/Format/SLAArchive.cpp new file mode 100644 index 000000000..8e2bf2824 --- /dev/null +++ b/src/libslic3r/Format/SLAArchive.cpp @@ -0,0 +1,74 @@ +#include "SLAArchive.hpp" + +#include "SL1.hpp" +#include "SL1_SVG.hpp" +#include "pwmx.hpp" + +#include "libslic3r/libslic3r.h" + +#include +#include +#include +#include + +namespace Slic3r { + +using ArchiveFactory = std::function(const SLAPrinterConfig&)>; + +struct ArchiveEntry { + const char *ext; + ArchiveFactory factoryfn; +}; + +static const std::map REGISTERED_ARCHIVES { + { + "SL1", + { "sl1", [] (const auto &cfg) { return std::make_unique(cfg); } } + }, + { + "SL2", + { "sl2", [] (const auto &cfg) { return std::make_unique(cfg); } } + }, + { + "pwmx", + { "pwmx", [] (const auto &cfg) { return std::make_unique(cfg); } } + } +}; + +std::unique_ptr +SLAArchive::create(const std::string &archtype, const SLAPrinterConfig &cfg) +{ + auto entry = REGISTERED_ARCHIVES.find(archtype); + + if (entry != REGISTERED_ARCHIVES.end()) + return entry->second.factoryfn(cfg); + + return nullptr; +} + +const std::vector& SLAArchive::registered_archives() +{ + static std::vector archnames; + + if (archnames.empty()) { + archnames.reserve(REGISTERED_ARCHIVES.size()); + + for (auto &[name, _] : REGISTERED_ARCHIVES) + archnames.emplace_back(name.c_str()); + } + + return archnames; +} + +const char *SLAArchive::get_extension(const char *archtype) +{ + static const char* DEFAULT_EXT = "zip"; + + auto entry = REGISTERED_ARCHIVES.find(archtype); + if (entry != REGISTERED_ARCHIVES.end()) + return entry->second.ext; + + return DEFAULT_EXT; +} + +} // namespace Slic3r diff --git a/src/libslic3r/Format/SLAArchive.hpp b/src/libslic3r/Format/SLAArchive.hpp new file mode 100644 index 000000000..971d7ba7b --- /dev/null +++ b/src/libslic3r/Format/SLAArchive.hpp @@ -0,0 +1,64 @@ +#ifndef SLAARCHIVE_HPP +#define SLAARCHIVE_HPP + +#include + +#include "libslic3r/SLA/RasterBase.hpp" +#include "libslic3r/Execution/ExecutionTBB.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" + +namespace Slic3r { + +class SLAPrint; +class SLAPrinterConfig; + +class SLAArchive { +protected: + std::vector m_layers; + + virtual std::unique_ptr create_raster() const = 0; + virtual sla::RasterEncoder get_encoder() const = 0; + +public: + virtual ~SLAArchive() = default; + + // Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid); + template + void draw_layers( + size_t layer_num, + Fn && drawfn, + CancelFn cancelfn = []() { return false; }, + const EP & ep = {}) + { + m_layers.resize(layer_num); + execution::for_each( + ep, size_t(0), m_layers.size(), + [this, &drawfn, &cancelfn](size_t idx) { + if (cancelfn()) return; + + sla::EncodedRaster &enc = m_layers[idx]; + auto rst = create_raster(); + drawfn(*rst, idx); + enc = rst->encode(get_encoder()); + }, + execution::max_concurrency(ep)); + } + + // Export the print into an archive using the provided filename. + virtual void export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &projectname = "") = 0; + + // Factory method to create an archiver instance + static std::unique_ptr create(const std::string &archtype, const SLAPrinterConfig&); + + // Get the names of currently known archiver implementations + static const std::vector & registered_archives(); + + // Get the default file extension belonging to an archive format + static const char *get_extension(const char *archtype); +}; + +} // namespace Slic3r +#endif // SLAARCHIVE_HPP diff --git a/src/libslic3r/Format/pwmx.cpp b/src/libslic3r/Format/pwmx.cpp index 5b420a49e..f3f0f6802 100644 --- a/src/libslic3r/Format/pwmx.cpp +++ b/src/libslic3r/Format/pwmx.cpp @@ -1,6 +1,7 @@ #include "pwmx.hpp" #include "GCode/ThumbnailData.hpp" #include "SLA/RasterBase.hpp" +#include "libslic3r/SLAPrint.hpp" #include #include @@ -277,8 +278,9 @@ void fill_header(pwmx_format_header &h, std::float_t bottle_volume_ml; std::float_t bottle_cost; std::float_t material_density; - auto & cfg = print.full_print_config(); - std::string mnotes = cfg.option("material_notes")->serialize(); + auto &cfg = print.full_print_config(); + auto mat_opt = cfg.option("material_notes"); + std::string mnotes = mat_opt? cfg.option("material_notes")->serialize() : ""; // create a config parser from the material notes Slic3r::PwmxFormatDynamicConfig mat_cfg; SLAPrintStatistics stats = print.print_statistics(); diff --git a/src/libslic3r/Format/pwmx.hpp b/src/libslic3r/Format/pwmx.hpp index d1179c014..65fb19910 100644 --- a/src/libslic3r/Format/pwmx.hpp +++ b/src/libslic3r/Format/pwmx.hpp @@ -3,7 +3,9 @@ #include -#include "libslic3r/SLAPrint.hpp" +#include "SLAArchive.hpp" + +#include "libslic3r/PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 2622b6a23..72cb96dd0 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -245,15 +245,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con // Handle changes to object config defaults m_default_object_config.apply_only(config, object_diff, true); - if (!m_archiver || !printer_diff.empty()) { - if (m_printer_config.sla_archive_format.value == "SL1") - m_archiver = std::make_unique(m_printer_config); - else if (m_printer_config.sla_archive_format.value == "SL2") - m_archiver = std::make_unique(m_printer_config); - else if (m_printer_config.sla_archive_format.value == "pwmx") { - m_archiver = std::make_unique(m_printer_config); - } - } + if (!m_archiver || !printer_diff.empty()) + m_archiver = SLAArchive::create(m_printer_config.sla_archive_format.value.c_str(), m_printer_config); struct ModelObjectStatus { enum Status { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 2d49139a4..0723382b3 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -9,6 +9,7 @@ #include "Point.hpp" #include "MTUtils.hpp" #include "Zipper.hpp" +#include "Format/SLAArchive.hpp" #include "GCode/ThumbnailData.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" @@ -390,45 +391,6 @@ struct SLAPrintStatistics } }; -class SLAArchive { -protected: - std::vector m_layers; - - virtual std::unique_ptr create_raster() const = 0; - virtual sla::RasterEncoder get_encoder() const = 0; - -public: - virtual ~SLAArchive() = default; - - // Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid); - template - void draw_layers( - size_t layer_num, - Fn && drawfn, - CancelFn cancelfn = []() { return false; }, - const EP & ep = {}) - { - m_layers.resize(layer_num); - execution::for_each( - ep, size_t(0), m_layers.size(), - [this, &drawfn, &cancelfn](size_t idx) { - if (cancelfn()) return; - - sla::EncodedRaster &enc = m_layers[idx]; - auto rst = create_raster(); - drawfn(*rst, idx); - enc = rst->encode(get_encoder()); - }, - execution::max_concurrency(ep)); - } - - // Export the print into an archive using the provided filename. - virtual void export_print(const std::string fname, - const SLAPrint &print, - const ThumbnailsList &thumbnails, - const std::string &projectname = "") = 0; -}; - /** * @brief This class is the high level FSM for the SLA printing process. * diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 1bb8cdf6c..96702d158 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -1,5 +1,6 @@ #include "SLAImportJob.hpp" +#include "libslic3r/SLAPrint.hpp" #include "libslic3r/Format/SL1.hpp" #include "slic3r/GUI/GUI.hpp" diff --git a/tests/libnest2d/CMakeLists.txt b/tests/libnest2d/CMakeLists.txt index bcb759452..9bafe84a0 100644 --- a/tests/libnest2d/CMakeLists.txt +++ b/tests/libnest2d/CMakeLists.txt @@ -4,4 +4,6 @@ target_link_libraries(${_TEST_NAME}_tests test_common libnest2d ) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") -add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]") +set(_catch_args "exclude:[NotWorking]") +list(APPEND _catch_args "${CATCH_EXTRA_ARGS}") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args}) diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index dc583f1a1..26d576549 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -3,7 +3,8 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp sla_print_tests.cpp sla_test_utils.hpp sla_test_utils.cpp sla_supptgen_tests.cpp - sla_raycast_tests.cpp) + sla_raycast_tests.cpp + sla_archive_export_tests.cpp) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/sla_print/sla_archive_export_tests.cpp b/tests/sla_print/sla_archive_export_tests.cpp new file mode 100644 index 000000000..586b0eb67 --- /dev/null +++ b/tests/sla_print/sla_archive_export_tests.cpp @@ -0,0 +1,37 @@ +#include +#include + +#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/Format/SLAArchive.hpp" + +#include + +using namespace Slic3r; + +TEST_CASE("Archive export test", "[sla_archives]") { + constexpr const char *PNAME = "20mm_cube"; + + for (auto &archname : SLAArchive::registered_archives()) { + INFO(std::string("Testing archive type: ") + archname); + SLAPrint print; + SLAFullPrintConfig fullcfg; + + auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(PNAME) + ".obj", nullptr); + + fullcfg.set("sla_archive_format", archname); + + DynamicPrintConfig cfg; + cfg.apply(fullcfg); + + print.apply(m, cfg); + print.process(); + + ThumbnailsList thumbnails; + auto outputfname = std::string("output.") + SLAArchive::get_extension(archname); + + print.export_print(outputfname, thumbnails, PNAME); + + // Not much can be checked about the archives... + REQUIRE(boost::filesystem::exists(outputfname)); + } +} diff --git a/tests/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index be1b645d7..256e6efd6 100644 --- a/tests/slic3rutils/CMakeLists.txt +++ b/tests/slic3rutils/CMakeLists.txt @@ -15,4 +15,6 @@ if (WIN32) endif() # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") -add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]") +set(_catch_args "exclude:[NotWorking]") +list(APPEND _catch_args "${CATCH_EXTRA_ARGS}") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args}) From b407540f268e949d2efc8769000aa1b6ea763778 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 17 Feb 2022 13:43:11 +0100 Subject: [PATCH 20/27] Downgrade log message from sla support tree creation --- src/libslic3r/SLA/SupportTreeBuildsteps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/SLA/SupportTreeBuildsteps.cpp b/src/libslic3r/SLA/SupportTreeBuildsteps.cpp index 6134e1f5a..aa69fdc77 100644 --- a/src/libslic3r/SLA/SupportTreeBuildsteps.cpp +++ b/src/libslic3r/SLA/SupportTreeBuildsteps.cpp @@ -982,7 +982,7 @@ bool SupportTreeBuildsteps::connect_to_model_body(Head &head) double w = dist - 2 * head.r_pin_mm - head.r_back_mm; if (w < 0.) { - BOOST_LOG_TRIVIAL(error) << "Pinhead width is negative!"; + BOOST_LOG_TRIVIAL(warning) << "Pinhead width is negative!"; w = 0.; } From b8718f46015c3e09ad6042ee6ce24cca636b88b9 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 17 Feb 2022 14:05:45 +0100 Subject: [PATCH 21/27] Silence sla print messages for archive export tests --- tests/sla_print/sla_archive_export_tests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/sla_print/sla_archive_export_tests.cpp b/tests/sla_print/sla_archive_export_tests.cpp index 586b0eb67..4cfdd0cdc 100644 --- a/tests/sla_print/sla_archive_export_tests.cpp +++ b/tests/sla_print/sla_archive_export_tests.cpp @@ -23,6 +23,7 @@ TEST_CASE("Archive export test", "[sla_archives]") { DynamicPrintConfig cfg; cfg.apply(fullcfg); + print.set_status_callback([](const PrintBase::SlicingStatus&) {}); print.apply(m, cfg); print.process(); From 4f2772fef493a98ac05b11d89c36047b02485dd1 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 18 Feb 2022 14:29:09 +0100 Subject: [PATCH 22/27] Fix sla archive tests --- tests/sla_print/CMakeLists.txt | 4 ++++ tests/sla_print/sla_archive_export_tests.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index 26d576549..88c1cd186 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -8,5 +8,9 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") +if (WIN32) + prusaslicer_copy_dlls(${_TEST_NAME}_tests) +endif() + # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${CATCH_EXTRA_ARGS}) diff --git a/tests/sla_print/sla_archive_export_tests.cpp b/tests/sla_print/sla_archive_export_tests.cpp index 4cfdd0cdc..9dbe5bc64 100644 --- a/tests/sla_print/sla_archive_export_tests.cpp +++ b/tests/sla_print/sla_archive_export_tests.cpp @@ -19,6 +19,8 @@ TEST_CASE("Archive export test", "[sla_archives]") { auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(PNAME) + ".obj", nullptr); fullcfg.set("sla_archive_format", archname); + fullcfg.set("supports_enable", false); + fullcfg.set("pad_enable", false); DynamicPrintConfig cfg; cfg.apply(fullcfg); From fe14c547fe95bed94a8ddef33c876f6f88e3d4d3 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 19 Feb 2022 12:49:23 +0100 Subject: [PATCH 23/27] Show GLEW error string on glewInit() initialization errors --- src/slic3r/GUI/OpenGLManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index 6616cc20d..41a11cff6 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -233,8 +233,9 @@ OpenGLManager::~OpenGLManager() bool OpenGLManager::init_gl() { if (!m_gl_initialized) { - if (glewInit() != GLEW_OK) { - BOOST_LOG_TRIVIAL(error) << "Unable to init glew library"; + GLenum err = glewInit(); + if (err != GLEW_OK) { + BOOST_LOG_TRIVIAL(error) << "Unable to init glew library: " << glewGetErrorString(err); return false; } m_gl_initialized = true; From 3a821d6752fa78880c99e2387a8a832d617c9d95 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 19 Feb 2022 12:53:37 +0100 Subject: [PATCH 24/27] Add missing declaration/includes (fix non-PCH build) --- src/libslic3r/Format/SL1.hpp | 2 ++ src/libslic3r/Format/SL1_SVG.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp index 8ed9dc329..493550db4 100644 --- a/src/libslic3r/Format/SL1.hpp +++ b/src/libslic3r/Format/SL1.hpp @@ -8,6 +8,8 @@ #include "libslic3r/Zipper.hpp" #include "libslic3r/PrintConfig.hpp" +struct indexed_triangle_set; + namespace Slic3r { class SL1Archive: public SLAArchive { diff --git a/src/libslic3r/Format/SL1_SVG.cpp b/src/libslic3r/Format/SL1_SVG.cpp index a7a8c9ed6..372348283 100644 --- a/src/libslic3r/Format/SL1_SVG.cpp +++ b/src/libslic3r/Format/SL1_SVG.cpp @@ -2,6 +2,7 @@ #include "SLA/RasterBase.hpp" #include "libslic3r/LocalesUtils.hpp" #include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/BoundingBox.hpp" #include #include From 0ffcfd8393457fd035576436752267c9a1e6bbcc Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 24 Jan 2022 20:21:24 +0100 Subject: [PATCH 25/27] Use namespaces to link against libcereal >= 1.3.1 Create an alias for previous versions. --- CMakeLists.txt | 3 +++ src/CMakeLists.txt | 2 +- src/libslic3r/CMakeLists.txt | 2 +- src/slic3r/CMakeLists.txt | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 72fd87d22..ba458ec96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -506,6 +506,9 @@ endif () # Find the Cereal serialization library find_package(cereal REQUIRED) +if (NOT TARGET cereal::cereal) + add_library(cereal::cereal ALIAS cereal) +endif () # l10n set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab1c7b964..bd5eb94a5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,7 +126,7 @@ if (NOT WIN32 AND NOT APPLE) set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer") endif () -target_link_libraries(PrusaSlicer libslic3r cereal) +target_link_libraries(PrusaSlicer libslic3r cereal::cereal) if (APPLE) # add_compile_options(-stdlib=libc++) # add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE) diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 046aba763..36344ebab 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -358,7 +358,7 @@ find_package(JPEG REQUIRED) target_link_libraries(libslic3r libnest2d admesh - cereal + cereal::cereal libigl miniz boost_libs diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 34c0efd01..b23db9867 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -270,7 +270,7 @@ endforeach() encoding_check(libslic3r_gui) -target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES}) +target_link_libraries(libslic3r_gui libslic3r avrdude cereal::cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES}) if (MSVC) target_link_libraries(libslic3r_gui Setupapi.lib) From cc788ebb643b6d4048f3550235ac3e9d3697ada0 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 22 Feb 2022 11:36:27 +0100 Subject: [PATCH 26/27] Fix and merge PR #7809 --- CMakeLists.txt | 7 +++++-- src/CMakeLists.txt | 2 +- src/libslic3r/CMakeLists.txt | 2 +- src/slic3r/CMakeLists.txt | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba458ec96..6c6afe671 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -506,9 +506,12 @@ endif () # Find the Cereal serialization library find_package(cereal REQUIRED) +add_library(libcereal INTERFACE) if (NOT TARGET cereal::cereal) - add_library(cereal::cereal ALIAS cereal) -endif () + target_link_libraries(libcereal INTERFACE cereal) +else() + target_link_libraries(libcereal INTERFACE cereal::cereal) +endif() # l10n set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd5eb94a5..61a2a90d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,7 +126,7 @@ if (NOT WIN32 AND NOT APPLE) set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer") endif () -target_link_libraries(PrusaSlicer libslic3r cereal::cereal) +target_link_libraries(PrusaSlicer libslic3r libcereal) if (APPLE) # add_compile_options(-stdlib=libc++) # add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE) diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 36344ebab..5e8d681f1 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -358,7 +358,7 @@ find_package(JPEG REQUIRED) target_link_libraries(libslic3r libnest2d admesh - cereal::cereal + libcereal libigl miniz boost_libs diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index b23db9867..022bba2a8 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -270,7 +270,7 @@ endforeach() encoding_check(libslic3r_gui) -target_link_libraries(libslic3r_gui libslic3r avrdude cereal::cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES}) +target_link_libraries(libslic3r_gui libslic3r avrdude libcereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES}) if (MSVC) target_link_libraries(libslic3r_gui Setupapi.lib) From 4ed411f211ea4ef4efa0aeb82aae9c9c0d991b8c Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 22 Feb 2022 12:41:51 +0100 Subject: [PATCH 27/27] Fix tbb assert when grainsize is lower then 1 --- src/libslic3r/Execution/Execution.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Execution/Execution.hpp b/src/libslic3r/Execution/Execution.hpp index 62e49cfeb..dcfd86bde 100644 --- a/src/libslic3r/Execution/Execution.hpp +++ b/src/libslic3r/Execution/Execution.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "libslic3r/libslic3r.h" @@ -44,7 +45,8 @@ size_t max_concurrency(const EP &ep) template> void for_each(const EP &ep, It from, It to, Fn &&fn, size_t granularity = 1) { - AsTraits::for_each(ep, from, to, std::forward(fn), granularity); + AsTraits::for_each(ep, from, to, std::forward(fn), + std::max(granularity, size_t(1))); } // A reduce operation with the execution policy passed as argument. @@ -68,7 +70,7 @@ T reduce(const EP & ep, return AsTraits::reduce(ep, from, to, init, std::forward(mergefn), std::forward(accessfn), - granularity); + std::max(granularity, size_t(1))); } // An overload of reduce method to be used with iterators as 'from' and 'to' @@ -87,7 +89,7 @@ T reduce(const EP &ep, { return reduce( ep, from, to, init, std::forward(mergefn), - [](const auto &i) { return i; }, granularity); + [](const auto &i) { return i; }, std::max(granularity, size_t(1))); } template{}, - std::forward(accessfn), granularity); + std::forward(accessfn), + std::max(granularity, size_t(1))); } @@ -119,7 +122,7 @@ T accumulate(const EP &ep, { return reduce( ep, from, to, init, std::plus{}, [](const auto &i) { return i; }, - granularity); + std::max(granularity, size_t(1))); } } // namespace execution_policy