diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index a4237880f..f943934b5 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -185,7 +185,8 @@ static bool vertex_equal_to_point(const Voronoi::VD::vertex_type &vertex, const ulp_cmp(vertex.y(), double(ipt.y()), ULPS) == ulp_cmp_type::EQUAL; } -static inline bool vertex_equal_to_point(const Voronoi::VD::vertex_type *vertex, const Point &ipt) { +static inline bool vertex_equal_to_point(const Voronoi::VD::vertex_type *vertex, const Point &ipt) +{ return vertex_equal_to_point(*vertex, ipt); } @@ -235,6 +236,10 @@ static std::vector colorize_line(const Line & line_to_ std::vector filtered_lines; filtered_lines.emplace_back(internal_painted.front()); for (size_t line_idx = 1; line_idx < internal_painted.size(); ++line_idx) { + // line_to_process is already all colored. Skip another possible duplicate coloring. + if(filtered_lines.back().projected_line.b == line_to_process.b) + break; + PaintedLine &prev = filtered_lines.back(); PaintedLine &curr = internal_painted[line_idx]; @@ -525,7 +530,7 @@ struct MMU_Graph nodes[to_idx].remove_edge(from_idx); } - size_t get_global_index(const size_t poly_idx, const size_t point_idx) const { return polygon_idx_offset[poly_idx] + point_idx; } + [[nodiscard]] size_t get_global_index(const size_t poly_idx, const size_t point_idx) const { return polygon_idx_offset[poly_idx] + point_idx; } void append_edge(const size_t &from_idx, const size_t &to_idx, int color = -1, ARC_TYPE type = ARC_TYPE::NON_BORDER) { @@ -546,7 +551,7 @@ struct MMU_Graph // Ignoring arcs in the opposite direction MMU_Graph::Arc get_arc(size_t idx) { return this->arcs[idx * 2]; } - size_t nodes_count() const { return this->nodes.size(); } + [[nodiscard]] size_t nodes_count() const { return this->nodes.size(); } void remove_nodes_with_one_arc() { @@ -602,12 +607,12 @@ struct MMU_Graph return vertex->color() < this->all_border_points; } - inline bool is_edge_attach_to_contour(const voronoi_diagram::const_edge_iterator &edge_iterator) const + [[nodiscard]] inline bool is_edge_attach_to_contour(const voronoi_diagram::const_edge_iterator &edge_iterator) const { return this->is_vertex_on_contour(edge_iterator->vertex0()) || this->is_vertex_on_contour(edge_iterator->vertex1()); } - inline bool is_edge_connecting_two_contour_vertices(const voronoi_diagram::const_edge_iterator &edge_iterator) const + [[nodiscard]] inline bool is_edge_connecting_two_contour_vertices(const voronoi_diagram::const_edge_iterator &edge_iterator) const { return this->is_vertex_on_contour(edge_iterator->vertex0()) && this->is_vertex_on_contour(edge_iterator->vertex1()); } @@ -1130,19 +1135,20 @@ static void cut_segmented_layers(const std::vector const float cut_width, const std::function &throw_on_cancel_callback) { + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin"; tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()),[&](const tbb::blocked_range& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); std::vector> segmented_regions_cuts; for (const std::pair &colored_expoly : segmented_regions[layer_idx]) { ExPolygons cut_colored_expoly = diff_ex(colored_expoly.first, offset_ex(input_expolygons[layer_idx], cut_width)); - for (const ExPolygon &expoly : cut_colored_expoly) { - segmented_regions_cuts.emplace_back(expoly, colored_expoly.second); - } + for (ExPolygon &expoly : cut_colored_expoly) + segmented_regions_cuts.emplace_back(std::move(expoly), colored_expoly.second); } - segmented_regions[layer_idx] = segmented_regions_cuts; + segmented_regions[layer_idx] = std::move(segmented_regions_cuts); } }); // end of parallel_for + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - end"; } // Returns MMU segmentation of top and bottom layers based on painting in MMU segmentation gizmo @@ -1154,6 +1160,8 @@ static inline std::vector> mmu_segmentation_top_and_bott const ConstLayerPtrsAdaptor layers = print_object.layers(); std::vector> triangles_by_color(num_extruders); triangles_by_color.assign(num_extruders, std::vector(layers.size())); + + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - begin"; for (const ModelVolume *mv : print_object.model_object()->volumes) { for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) { throw_on_cancel_callback(); @@ -1203,6 +1211,7 @@ static inline std::vector> mmu_segmentation_top_and_bott } } } + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - end"; auto get_extrusion_width = [&layers = std::as_const(layers)](const size_t layer_idx) -> float { auto extrusion_width_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(), @@ -1272,8 +1281,8 @@ static inline std::vector> mmu_segmentation_top_and_bott triangles_by_color_bottom.assign(num_extruders, std::vector(input_expolygons.size())); triangles_by_color_top.assign(num_extruders, std::vector(input_expolygons.size())); + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - begin"; for (size_t layer_idx = 0; layer_idx < input_expolygons.size(); ++layer_idx) { - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of top layer: " << layer_idx; float extrusion_width = scale_(get_extrusion_width(layer_idx)); int top_solid_layers = get_top_solid_layers(layer_idx); ExPolygons top_expolygon = top_layers[layer_idx]; @@ -1306,9 +1315,10 @@ static inline std::vector> mmu_segmentation_top_and_bott } } } + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - end"; + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - begin"; for (size_t layer_idx = 0; layer_idx < input_expolygons.size(); ++layer_idx) { - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of bottom layer: " << layer_idx; float extrusion_width = scale_(get_extrusion_width(layer_idx)); int bottom_solid_layers = get_bottom_solid_layers(layer_idx); const ExPolygons &bottom_expolygon = bottom_layers[layer_idx]; @@ -1340,6 +1350,7 @@ static inline std::vector> mmu_segmentation_top_and_bott } } } + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - end"; std::vector> triangles_by_color_merged(num_extruders); triangles_by_color_merged.assign(num_extruders, std::vector(input_expolygons.size())); @@ -1369,23 +1380,27 @@ static std::vector>> merge_segmented_la { std::vector>> segmented_regions_merged(segmented_regions.size()); + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - begin"; tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()), [&](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging region: " << layer_idx; for (const std::pair &colored_expoly : segmented_regions[layer_idx]) { throw_on_cancel_callback(); + // Zero is the default color of the volume. + if(colored_expoly.second == 0) + continue; ExPolygons cut_colored_expoly = {colored_expoly.first}; for (const std::vector &top_and_bottom_layer : top_and_bottom_layers) cut_colored_expoly = diff_ex(cut_colored_expoly, top_and_bottom_layer[layer_idx]); for (ExPolygon &ex_poly : cut_colored_expoly) - segmented_regions_merged[layer_idx].emplace_back(std::move(ex_poly), colored_expoly.second); + segmented_regions_merged[layer_idx].emplace_back(std::move(ex_poly), colored_expoly.second - 1); } - for (size_t color_idx = 0; color_idx < top_and_bottom_layers.size(); ++color_idx) + for (size_t color_idx = 1; color_idx < top_and_bottom_layers.size(); ++color_idx) for (ExPolygon &expoly : top_and_bottom_layers[color_idx][layer_idx]) - segmented_regions_merged[layer_idx].emplace_back(std::move(expoly), color_idx); + segmented_regions_merged[layer_idx].emplace_back(std::move(expoly), color_idx - 1); } }); // end of parallel_for + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - end"; return segmented_regions_merged; } @@ -1402,13 +1417,14 @@ std::vector>> multi_material_segmentati throw_on_cancel_callback(); // Merge all regions and remove small holes + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - begin"; tbb::parallel_for(tbb::blocked_range(0, layers.size()), [&](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); ExPolygons ex_polygons; for (LayerRegion *region : layers[layer_idx]->regions()) for (const Surface &surface : region->slices.surfaces) - Slic3r::append(ex_polygons, offset_ex(surface.expolygon, float(SCALED_EPSILON))); + Slic3r::append(ex_polygons, offset_ex(surface.expolygon, float(10 * SCALED_EPSILON))); // All expolygons are expanded by SCALED_EPSILON, merged, and then shrunk again by SCALED_EPSILON // to ensure that very close polygons will be merged. ex_polygons = union_ex(ex_polygons); @@ -1421,19 +1437,22 @@ std::vector>> multi_material_segmentati // Such close points sometimes caused that the Voronoi diagram has self-intersecting edges around these vertices. // This consequently leads to issues with the extraction of colored segments by function extract_colored_segments. // Calling expolygons_simplify fixed these issues. - input_expolygons[layer_idx] = simplify_polygons_ex(to_polygons(expolygons_simplify(offset_ex(ex_polygons, float(-SCALED_EPSILON)), SCALED_EPSILON))); + input_expolygons[layer_idx] = simplify_polygons_ex(to_polygons(expolygons_simplify(offset_ex(ex_polygons, float(-10 * SCALED_EPSILON)), 5 * SCALED_EPSILON))); input_polygons[layer_idx] = to_polygons(input_expolygons[layer_idx]); } }); // end of parallel_for + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - end"; for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { throw_on_cancel_callback(); BoundingBox bbox(get_extents(input_expolygons[layer_idx])); - bbox.offset(SCALED_EPSILON); + // Projected triangles may slightly exceed the input polygons. + bbox.offset(20 * SCALED_EPSILON); edge_grids[layer_idx].set_bbox(bbox); edge_grids[layer_idx].create(input_expolygons[layer_idx], coord_t(scale_(10.))); } + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - begin"; for (const ModelVolume *mv : print_object.model_object()->volumes) { const size_t num_extruders = print_object.print()->config().nozzle_diameter.size(); for (size_t extruder_idx = 1; extruder_idx < num_extruders; ++extruder_idx) { @@ -1500,20 +1519,23 @@ std::vector>> multi_material_segmentati } } } + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - end"; + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - painted layers count: " + << std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector &pl) { return !pl.empty(); }); + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin"; tbb::parallel_for(tbb::blocked_range(0, print_object.layers().size()), [&](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); - // for(size_t layer_idx = 0; layer_idx < print_object.layers().size(); ++layer_idx) { - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of layer: " << layer_idx; - auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) { - Point first_start_p = *(edge_grids[layer_idx].contours()[first.contour_idx].begin() + first.line_idx); - + auto comp = [&input_polygons, layer_idx](const PaintedLine &first, const PaintedLine &second) { + Point first_start_p = input_polygons[layer_idx][first.contour_idx][first.line_idx]; return first.contour_idx < second.contour_idx || (first.contour_idx == second.contour_idx && (first.line_idx < second.line_idx || (first.line_idx == second.line_idx && - Line(first_start_p, first.projected_line.a).length() < Line(first_start_p, second.projected_line.a).length()))); + ((first.projected_line.a - first_start_p).cast().squaredNorm() < (second.projected_line.a - first_start_p).cast().squaredNorm() || + ((first.projected_line.a - first_start_p).cast().squaredNorm() == (second.projected_line.a - first_start_p).cast().squaredNorm() && + (first.projected_line.b - first.projected_line.a).cast().squaredNorm() < (second.projected_line.b - second.projected_line.a).cast().squaredNorm()))))); }; std::sort(painted_lines[layer_idx].begin(), painted_lines[layer_idx].end(), comp); @@ -1525,11 +1547,12 @@ std::vector>> multi_material_segmentati remove_multiple_edges_in_vertices(graph, color_poly); graph.remove_nodes_with_one_arc(); std::vector> segmentation = extract_colored_segments(graph); - for (const std::pair ®ion : segmentation) - segmented_regions[layer_idx].emplace_back(region); + for (std::pair ®ion : segmentation) + segmented_regions[layer_idx].emplace_back(std::move(region)); } } }); // end of parallel_for + BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - end"; throw_on_cancel_callback(); if (auto w = print_object.config().mmu_segmented_region_max_width; w > 0.f) { diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 976e35391..52085b178 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -12,7 +12,7 @@ namespace Slic3r { #ifndef _NDEBUG bool TriangleSelector::verify_triangle_midpoints(const Triangle &tr) const { - for (int i = 0; i < 3; ++ i) { + for (int i = 0; i < 3; ++ i) { int v1 = tr.verts_idxs[i]; int v2 = tr.verts_idxs[next_idx_modulo(i, 3)]; int vmid = this->triangle_midpoint(tr, v1, v2); @@ -168,7 +168,7 @@ bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type, for (int i = 0; i < 3; ++ i) neighbors(i) = neighbors_src.neighbor[i]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); - + if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting)) return false; @@ -249,11 +249,11 @@ int TriangleSelector::triangle_midpoint(const Triangle &tr, int vertexi, int ver assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj); if (tr.number_of_split_sides() == 1) { - return edge == next_idx_modulo(tr.special_side(), 3) ? + return edge == next_idx_modulo(tr.special_side(), 3) ? m_triangles[tr.children[0]].verts_idxs[2] : this->triangle_midpoint(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj); } else if (tr.number_of_split_sides() == 2) { - return edge == next_idx_modulo(tr.special_side(), 3) ? + return edge == next_idx_modulo(tr.special_side(), 3) ? this->triangle_midpoint(m_triangles[tr.children[2]], vertexi, vertexj) : edge == tr.special_side() ? m_triangles[tr.children[0]].verts_idxs[1] : @@ -261,7 +261,7 @@ int TriangleSelector::triangle_midpoint(const Triangle &tr, int vertexi, int ver } else { assert(tr.number_of_split_sides() == 3); assert(tr.special_side() == 0); - return + return (edge == 0) ? m_triangles[tr.children[0]].verts_idxs[1] : (edge == 1) ? m_triangles[tr.children[1]].verts_idxs[2] : m_triangles[tr.children[2]].verts_idxs[2]; @@ -282,7 +282,7 @@ int TriangleSelector::triangle_midpoint_or_allocate(int itriangle, int vertexi, Vec3f c = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v); #ifdef EXPENSIVE_DEBUG_CHECKS // Verify that the vertex is really a new one. - auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [this, c](const Vertex &v) { + auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [this, c](const Vertex &v) { return v.ref_cnt > 0 && (v.v - c).norm() < EPSILON; }); assert(it == m_vertices.end()); #endif // EXPENSIVE_DEBUG_CHECKS @@ -736,7 +736,7 @@ TriangleSelector::TriangleSelector(const TriangleMesh& mesh) } -void TriangleSelector::reset(const EnforcerBlockerType reset_state) +void TriangleSelector::reset() { m_vertices.clear(); m_triangles.clear(); @@ -749,10 +749,10 @@ void TriangleSelector::reset(const EnforcerBlockerType reset_state) m_triangles.reserve(m_mesh->its.indices.size()); for (size_t i=0; iits.indices.size(); ++i) { const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i]; - push_triangle(ind[0], ind[1], ind[2], i, reset_state); + push_triangle(ind[0], ind[1], ind[2], i); } m_orig_size_vertices = m_vertices.size(); - m_orig_size_indices = m_triangles.size(); + m_orig_size_indices = m_triangles.size(); } @@ -930,8 +930,8 @@ std::pair>, std::vector> TriangleSelector: // In case this is leaf, we better save information about its state. int n = int(tr.get_state()); if (n >= 3) { - assert(n <= 15); - if (n <= 15) { + assert(n <= 16); + if (n <= 16) { // Store "11" plus 4 bits of (n-3). data.second.insert(data.second.end(), { true, true }); n -= 3; @@ -963,9 +963,9 @@ std::pair>, std::vector> TriangleSelector: return out.data; } -void TriangleSelector::deserialize(const std::pair>, std::vector> &data, const EnforcerBlockerType init_state) +void TriangleSelector::deserialize(const std::pair>, std::vector> &data) { - reset(init_state); // dump any current state + reset(); // dump any current state // Vector to store all parents that have offsprings. struct ProcessingInfo { @@ -1058,7 +1058,7 @@ void TriangleSelector::deserialize(const std::pair>, std::vector> serialize() const; // Load serialized data. Assumes that correct mesh is loaded. - void deserialize(const std::pair>, std::vector> &data, const EnforcerBlockerType init_state = EnforcerBlockerType{0}); + void deserialize(const std::pair>, std::vector> &data); // For all triangles, remove the flag indicating that the triangle was selected by seed fill. void seed_fill_unselect_all_triangles(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index daf8c5991..9662bacc0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1168,10 +1168,11 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject const GLGizmosManager& gm = get_gizmos_manager(); auto gizmo_type = gm.get_current_type(); if ( (gizmo_type == GLGizmosManager::FdmSupports - || gizmo_type == GLGizmosManager::Seam - || gizmo_type == GLGizmosManager::MmuSegmentation) + || gizmo_type == GLGizmosManager::Seam) && ! vol->is_modifier) vol->force_neutral_color = true; + else if (gizmo_type == GLGizmosManager::MmuSegmentation) + vol->is_active = false; else vol->force_native_color = true; } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 53fbc4c1c..bd0e4923b 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2201,9 +2201,9 @@ void ObjectList::part_selection_changed() if (type == itInfo) { InfoItemType info_type = m_objects_model->GetInfoItemType(item); if (info_type != InfoItemType::VariableLayerHeight) { - GLGizmosManager::EType gizmo_type = - info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports - : GLGizmosManager::EType::Seam; + GLGizmosManager::EType gizmo_type = info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports : + info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam : + GLGizmosManager::EType::MmuSegmentation; GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); if (gizmos_mgr.get_current_type() != gizmo_type) gizmos_mgr.open_gizmo(gizmo_type); @@ -2333,6 +2333,7 @@ void ObjectList::update_info_items(size_t obj_idx) for (InfoItemType type : {InfoItemType::CustomSupports, InfoItemType::CustomSeam, + InfoItemType::MmuSegmentation, InfoItemType::VariableLayerHeight}) { wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type); bool shows = item.IsOk(); @@ -2341,12 +2342,13 @@ void ObjectList::update_info_items(size_t obj_idx) switch (type) { case InfoItemType::CustomSupports : case InfoItemType::CustomSeam : + case InfoItemType::MmuSegmentation : should_show = printer_technology() == ptFFF && std::any_of(model_object->volumes.begin(), model_object->volumes.end(), - [type](const ModelVolume* mv) { - return ! (type == InfoItemType::CustomSupports - ? mv->supported_facets.empty() - : mv->seam_facets.empty()); + [type](const ModelVolume *mv) { + return !(type == InfoItemType::CustomSupports ? mv->supported_facets.empty() : + type == InfoItemType::CustomSeam ? mv->seam_facets.empty() : + mv->mmu_segmentation_facets.empty()); }); break; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 8c903470d..3274f000c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -103,10 +103,10 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); const float minimal_slider_width = m_imgui->scaled(4.f); - float caption_max = 0.f; - float total_text_max = 0.; - for (const std::string& t : {"enforce", "block", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); + float caption_max = 0.f; + float total_text_max = 0.f; + for (const auto &t : std::array{"enforce", "block", "remove"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); } caption_max += m_imgui->scaled(1.f); @@ -124,7 +124,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(text); }; - for (const std::string& t : {"enforce", "block", "remove"}) + for (const auto &t : std::array{"enforce", "block", "remove"}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); m_imgui->text(""); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index e04a5c49d..50d74e047 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -7,6 +7,7 @@ #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/BitmapCache.hpp" #include "slic3r/GUI/format.hpp" +#include "slic3r/GUI/GUI_ObjectList.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Model.hpp" @@ -32,15 +33,15 @@ bool GLGizmoMmuSegmentation::on_is_selectable() const && wxGetApp().get_mode() != comSimple && wxGetApp().extruders_edited_cnt() > 1); } -static std::vector> get_extruders_colors() +static std::vector> get_extruders_colors() { - unsigned char rgb_color[3] = {}; - std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - std::vector> colors_out(colors.size()); + unsigned char rgb_color[3] = {}; + std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); + std::vector> colors_out(colors.size()); for (const std::string &color : colors) { Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); size_t color_idx = &color - &colors.front(); - colors_out[color_idx] = {rgb_color[0], rgb_color[1], rgb_color[2]}; + colors_out[color_idx] = {float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f}; } return colors_out; @@ -57,6 +58,20 @@ static std::vector get_extruders_names() return extruders_out; } +static std::vector get_extruder_id_for_volumes(const ModelObject &model_object) +{ + std::vector extruders_idx; + extruders_idx.reserve(model_object.volumes.size()); + for (const ModelVolume *model_volume : model_object.volumes) { + if (!model_volume->is_model_part()) + continue; + + extruders_idx.emplace_back(model_volume->extruder_id()); + } + + return extruders_idx; +} + void GLGizmoMmuSegmentation::init_extruders_data() { m_original_extruders_names = get_extruders_names(); @@ -98,7 +113,7 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() const glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - render_triangles(selection); + render_triangles(selection, false); m_c->object_clipper()->render_cut(); render_cursor(); @@ -113,25 +128,31 @@ void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection) if (m_state != On) return; - int prev_extruders_count = int(m_original_extruders_colors.size()); + ModelObject *model_object = m_c->selection_info()->model_object(); + int prev_extruders_count = int(m_original_extruders_colors.size()); if (prev_extruders_count != wxGetApp().extruders_edited_cnt() || get_extruders_colors() != m_original_extruders_colors) { this->init_extruders_data(); // Reinitialize triangle selectors because of change of extruder count need also change the size of GLIndexedVertexArray if (prev_extruders_count != wxGetApp().extruders_edited_cnt()) this->init_model_triangle_selectors(); + } else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_original_volumes_extruder_idxs) { + this->init_model_triangle_selectors(); } } -static void render_extruders_combo(const std::string &label, - const std::vector &extruders, - const std::vector> &extruders_colors, - size_t &selection_idx) +static void render_extruders_combo(const std::string &label, + const std::vector &extruders, + const std::vector> &extruders_colors, + size_t &selection_idx) { assert(!extruders_colors.empty()); assert(extruders_colors.size() == extruders_colors.size()); - size_t selection_out = selection_idx; + auto convert_to_imu32 = [](const std::array &color) -> ImU32 { + return IM_COL32(uint8_t(color[0] * 255.f), uint8_t(color[1] * 255.f), uint8_t(color[2] * 255.f), uint8_t(color[3] * 255.f)); + }; + size_t selection_out = selection_idx; // It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox. ImGui::BeginGroup(); ImVec2 combo_pos = ImGui::GetCursorScreenPos(); @@ -146,8 +167,7 @@ static void render_extruders_combo(const std::string &la ImGui::SameLine(); ImGuiStyle &style = ImGui::GetStyle(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), - IM_COL32(extruders_colors[extruder_idx][0], extruders_colors[extruder_idx][1], extruders_colors[extruder_idx][2], 255)); + ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), convert_to_imu32(extruders_colors[extruder_idx])); ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y)); @@ -165,9 +185,7 @@ static void render_extruders_combo(const std::string &la ImVec2 p = ImGui::GetCursorScreenPos(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), - IM_COL32(extruders_colors[selection_idx][0], extruders_colors[selection_idx][1], - extruders_colors[selection_idx][2], 255)); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), convert_to_imu32(extruders_colors[selection_idx])); ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y)); @@ -206,7 +224,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott float caption_max = 0.f; float total_text_max = 0.; - for (const std::string &t : {"first_color", "second_color", "remove"}) { + for (const auto &t : std::array{"first_color", "second_color", "remove"}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); } @@ -225,33 +243,33 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(text); }; - for (const std::string &t : {"first_color", "second_color", "remove"}) + for (const auto &t : std::array{"first_color", "second_color", "remove"}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); m_imgui->text(""); ImGui::Separator(); - const std::array &select_first_color = m_modified_extruders_colors[m_first_selected_extruder_idx]; - const std::array &select_second_color = m_modified_extruders_colors[m_second_selected_extruder_idx]; - m_imgui->text(m_desc.at("first_color")); ImGui::SameLine(combo_label_width); ImGui::PushItemWidth(window_width - combo_label_width - color_button_width); render_extruders_combo("##first_color_combo", m_original_extruders_names, m_original_extruders_colors, m_first_selected_extruder_idx); ImGui::SameLine(); - ImVec4 first_color = ImVec4(float(select_first_color[0]) / 255.0f, float(select_first_color[1]) / 255.0f, float(select_first_color[2]) / 255.0f, 1.0f); - ImVec4 second_color = ImVec4(float(select_second_color[0]) / 255.0f, float(select_second_color[1]) / 255.0f, float(select_second_color[2]) / 255.0f, 1.0f); + const std::array &select_first_color = m_modified_extruders_colors[m_first_selected_extruder_idx]; + ImVec4 first_color = ImVec4(select_first_color[0], select_first_color[1], select_first_color[2], select_first_color[3]); if(ImGui::ColorEdit4("First color##color_picker", (float*)&first_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) - m_modified_extruders_colors[m_first_selected_extruder_idx] = {uint8_t(first_color.x * 255.0f), uint8_t(first_color.y * 255.0f), uint8_t(first_color.z * 255.0f)}; + m_modified_extruders_colors[m_first_selected_extruder_idx] = {first_color.x, first_color.y, first_color.z, first_color.w}; m_imgui->text(m_desc.at("second_color")); ImGui::SameLine(combo_label_width); ImGui::PushItemWidth(window_width - combo_label_width - color_button_width); render_extruders_combo("##second_color_combo", m_original_extruders_names, m_original_extruders_colors, m_second_selected_extruder_idx); ImGui::SameLine(); + + const std::array &select_second_color = m_modified_extruders_colors[m_second_selected_extruder_idx]; + ImVec4 second_color = ImVec4(select_second_color[0], select_second_color[1], select_second_color[2], select_second_color[3]); if(ImGui::ColorEdit4("Second color##color_picker", (float*)&second_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) - m_modified_extruders_colors[m_second_selected_extruder_idx] = {uint8_t(second_color.x * 255.0f), uint8_t(second_color.y * 255.0f), uint8_t(second_color.z * 255.0f)}; + m_modified_extruders_colors[m_second_selected_extruder_idx] = {second_color.x, second_color.y, second_color.z, second_color.w}; ImGui::Separator(); @@ -279,8 +297,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott for (ModelVolume *mv : mo->volumes) { if (mv->is_model_part()) { ++idx; - size_t extruder_id = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; - m_triangle_selectors[idx]->reset(EnforcerBlockerType(extruder_id)); + m_triangle_selectors[idx]->reset(); } } @@ -375,8 +392,11 @@ void GLGizmoMmuSegmentation::update_model_object() const updated |= mv->mmu_segmentation_facets.set(*m_triangle_selectors[idx].get()); } - if (updated) + if (updated) { + const ModelObjectPtrs &mos = wxGetApp().model().objects; + wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + } } void GLGizmoMmuSegmentation::init_model_triangle_selectors() @@ -391,10 +411,11 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() // This mesh does not account for the possible Z up SLA offset. const TriangleMesh *mesh = &mv->mesh(); - size_t extruder_id = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; - m_triangle_selectors.emplace_back(std::make_unique(*mesh, m_modified_extruders_colors)); - m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), EnforcerBlockerType(extruder_id)); + int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; + m_triangle_selectors.emplace_back(std::make_unique(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)])); + m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data()); } + m_original_volumes_extruder_idxs = get_extruder_id_for_volumes(*mo); } void GLGizmoMmuSegmentation::update_from_model_object() @@ -410,79 +431,66 @@ PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const std::array GLGizmoMmuSegmentation::get_cursor_sphere_left_button_color() const { - const std::array &color = m_modified_extruders_colors[m_first_selected_extruder_idx]; - return {float(color[0]) / 255.0f, float(color[1]) / 255.0f, float(color[2]) / 255.0f, 0.25f}; + const std::array &color = m_modified_extruders_colors[m_first_selected_extruder_idx]; + return {color[0], color[1], color[2], 0.25f}; } std::array GLGizmoMmuSegmentation::get_cursor_sphere_right_button_color() const { - const std::array &color = m_modified_extruders_colors[m_second_selected_extruder_idx]; - return {float(color[0]) / 255.0f, float(color[1]) / 255.0f, float(color[2]) / 255.0f, 0.25f}; + const std::array &color = m_modified_extruders_colors[m_second_selected_extruder_idx]; + return {color[0], color[1], color[2], 0.25f}; } void TriangleSelectorMmuGui::render(ImGuiWrapper *imgui) { + static constexpr std::array seed_fill_color{0.f, 1.f, 0.44f, 1.f}; + std::vector color_cnt(m_iva_colors.size()); int seed_fill_cnt = 0; for (auto &iva_color : m_iva_colors) iva_color.release_geometry(); m_iva_seed_fill.release_geometry(); + auto append_triangle = [this](GLIndexedVertexArray &iva, int &cnt, const Triangle &tr) -> void { + for (int i = 0; i < 3; ++i) + iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); + iva.push_triangle(cnt, cnt + 1, cnt + 2); + cnt += 3; + }; + for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) { for (const Triangle &tr : m_triangles) { if (!tr.valid() || tr.is_split() || tr.is_selected_by_seed_fill() || tr.get_state() != EnforcerBlockerType(color_idx)) continue; - - for (int i = 0; i < 3; ++i) - m_iva_colors[color_idx].push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); - m_iva_colors[color_idx].push_triangle(color_cnt[color_idx], color_cnt[color_idx] + 1, color_cnt[color_idx] + 2); - color_cnt[color_idx] += 3; + append_triangle(m_iva_colors[color_idx], color_cnt[color_idx], tr); } } for (const Triangle &tr : m_triangles) { - if (!tr.valid() || tr.is_split() || !tr.is_selected_by_seed_fill()) continue; - - for (int i = 0; i < 3; ++i) - m_iva_seed_fill.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); - m_iva_seed_fill.push_triangle(seed_fill_cnt, seed_fill_cnt + 1, seed_fill_cnt + 2); - seed_fill_cnt += 3; + if (!tr.valid() || tr.is_split() || !tr.is_selected_by_seed_fill()) + continue; + append_triangle(m_iva_seed_fill, seed_fill_cnt, tr); } for (auto &iva_color : m_iva_colors) iva_color.finalize_geometry(true); m_iva_seed_fill.finalize_geometry(true); - std::vector render_colors(m_iva_colors.size()); - for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) - render_colors[color_idx] = m_iva_colors[color_idx].has_VBOs(); - bool render_seed_fill = m_iva_seed_fill.has_VBOs(); + auto *shader = wxGetApp().get_current_shader(); + if (!shader) + return; + assert(shader->get_name() == "gouraud"); - auto *shader = wxGetApp().get_shader("gouraud"); - if (!shader) return; - - shader->start_using(); - ScopeGuard guard([shader]() { - if (shader) - shader->stop_using(); - }); - shader->set_uniform("slope.actived", false); - shader->set_uniform("print_box.actived", false); - - for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) { - if (render_colors[color_idx]) { - std::array color = {float(m_colors[color_idx][0]) / 255.0f, float(m_colors[color_idx][1]) / 255.0f, - float(m_colors[color_idx][2]) / 255.0f, 1.f}; + auto render = [&shader](const GLIndexedVertexArray &iva, const std::array &color) -> void { + if (iva.has_VBOs()) { shader->set_uniform("uniform_color", color); - m_iva_colors[color_idx].render(); + iva.render(); } - } + }; - if (render_seed_fill) { - std::array color = {0.f, 1.f, 0.44f, 1.f}; - shader->set_uniform("uniform_color", color); - m_iva_seed_fill.render(); - } + for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) + render(m_iva_colors[color_idx], (color_idx == 0) ? m_default_volume_color : m_colors[color_idx - 1]); + render(m_iva_seed_fill, seed_fill_color); } wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 82b858d42..f5c97801b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -7,18 +7,22 @@ namespace Slic3r::GUI { class TriangleSelectorMmuGui : public TriangleSelectorGUI { public: - explicit TriangleSelectorMmuGui(const TriangleMesh& mesh, const std::vector> &colors) - : TriangleSelectorGUI(mesh), m_colors(colors) { - m_iva_colors = std::vector(colors.size()); + explicit TriangleSelectorMmuGui(const TriangleMesh& mesh, const std::vector> &colors, const std::array &default_volume_color) + : TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color) { + // Plus 1 is because the first position is allocated for non-painted triangles. + m_iva_colors = std::vector(colors.size() + 1); } + ~TriangleSelectorMmuGui() override = default; // Render current selection. Transformation matrices are supposed // to be already set. void render(ImGuiWrapper* imgui) override; private: - const std::vector> &m_colors; - std::vector m_iva_colors; + const std::vector> &m_colors; + std::vector m_iva_colors; + const std::array m_default_volume_color; + GLIndexedVertexArray m_iva_seed_fill; }; class GLGizmoMmuSegmentation : public GLGizmoPainterBase @@ -26,6 +30,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase public: GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoPainterBase(parent, icon_filename, sprite_id) {} + ~GLGizmoMmuSegmentation() override = default; void render_painter_gizmo() const override; @@ -35,8 +40,8 @@ protected: std::array get_cursor_sphere_left_button_color() const override; std::array get_cursor_sphere_right_button_color() const override; - EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_first_selected_extruder_idx); } - EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType(m_second_selected_extruder_idx); } + EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_first_selected_extruder_idx + 1); } + EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType(m_second_selected_extruder_idx + 1); } void on_render_input_window(float x, float y, float bottom_limit) override; std::string on_get_name() const override; @@ -45,11 +50,12 @@ protected: wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; - size_t m_first_selected_extruder_idx = 0; - size_t m_second_selected_extruder_idx = 1; - std::vector m_original_extruders_names; - std::vector> m_original_extruders_colors; - std::vector> m_modified_extruders_colors; + size_t m_first_selected_extruder_idx = 0; + size_t m_second_selected_extruder_idx = 1; + std::vector m_original_extruders_names; + std::vector> m_original_extruders_colors; + std::vector> m_modified_extruders_colors; + std::vector m_original_volumes_extruder_idxs; private: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 64b41e46e..3f8d5a007 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -13,8 +13,7 @@ -namespace Slic3r { -namespace GUI { +namespace Slic3r::GUI { GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) @@ -110,13 +109,15 @@ void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) -void GLGizmoPainterBase::render_triangles(const Selection& selection) const +void GLGizmoPainterBase::render_triangles(const Selection& selection, const bool use_polygon_offset_fill) const { const ModelObject* mo = m_c->selection_info()->model_object(); - glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); - ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } ); - glsafe(::glPolygonOffset(-5.0, -5.0)); + if (use_polygon_offset_fill) { + glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); + ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); }); + glsafe(::glPolygonOffset(-5.0, -5.0)); + } // Take care of the clipping plane. The normal of the clipping plane is // saved with opposite sign than we need to pass to OpenGL (FIXME) @@ -125,8 +126,8 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const if (clipping_plane_active) { const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); for (size_t i=0; i<3; ++i) - clp_dataf[i] = -1. * clp->get_data()[i]; - clp_dataf[3] = clp->get_data()[3]; + clp_dataf[i] = -1.f * float(clp->get_data()[i]); + clp_dataf[3] = float(clp->get_data()[3]); } auto *shader = wxGetApp().get_shader("gouraud"); @@ -202,13 +203,13 @@ void GLGizmoPainterBase::render_cursor() const void GLGizmoPainterBase::render_cursor_circle() const { - const Camera& camera = wxGetApp().plater()->get_camera(); - float zoom = (float)camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + const Camera &camera = wxGetApp().plater()->get_camera(); + auto zoom = (float) camera.get_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - Size cnv_size = m_parent.get_canvas_size(); - float cnv_half_width = 0.5f * (float)cnv_size.get_width(); - float cnv_half_height = 0.5f * (float)cnv_size.get_height(); + Size cnv_size = m_parent.get_canvas_size(); + float cnv_half_width = 0.5f * (float) cnv_size.get_width(); + float cnv_half_height = 0.5f * (float) cnv_size.get_height(); if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) return; Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); @@ -216,11 +217,8 @@ void GLGizmoPainterBase::render_cursor_circle() const center = center * inv_zoom; glsafe(::glLineWidth(1.5f)); - float color[3]; - color[0] = 0.f; - color[1] = 1.f; - color[2] = 0.3f; - glsafe(::glColor3fv(color)); + static const std::array color = {0.f, 1.f, 0.3f}; + glsafe(::glColor3fv(color.data())); glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); @@ -395,9 +393,10 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast(); assert(m_rr.mesh_id < int(m_triangle_selectors.size())); - if (m_seed_fill_enabled) + if (m_seed_fill_enabled) { m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state); - else + m_seed_fill_last_mesh_id = -1; + } else m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type, new_state, trafo_matrix, m_triangle_splitting_enabled); m_last_mouse_click = mouse_position; @@ -425,17 +424,27 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now "click" into all the prepared points and spill paint around them. update_raycast_cache(mouse_position, camera, trafo_matrices); - if (m_rr.mesh_id == -1) { - // Clean selected by seed fill for all triangles + auto seed_fill_unselect_all = [this]() { for (auto &triangle_selector : m_triangle_selectors) triangle_selector->seed_fill_unselect_all_triangles(); + }; + + if (m_rr.mesh_id == -1) { + // Clean selected by seed fill for all triangles in all meshes when a mouse isn't pointing on any mesh. + seed_fill_unselect_all(); + m_seed_fill_last_mesh_id = -1; // In case we have no valid hit, we can return. return false; } + // The mouse moved from one object's volume to another one. So it is needed to unselect all triangles selected by seed fill. + if(m_rr.mesh_id != m_seed_fill_last_mesh_id) + seed_fill_unselect_all(); + assert(m_rr.mesh_id < int(m_triangle_selectors.size())); m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle); + m_seed_fill_last_mesh_id = m_rr.mesh_id; return true; } @@ -514,11 +523,7 @@ bool GLGizmoPainterBase::on_is_activable() const // Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside. const Selection::IndicesList& list = selection.get_volume_idxs(); - for (const auto& idx : list) - if (selection.get_volume(idx)->is_outside) - return false; - - return true; + return std::all_of(list.cbegin(), list.cend(), [&selection](unsigned int idx) { return !selection.get_volume(idx)->is_outside; }); } bool GLGizmoPainterBase::on_is_selectable() const @@ -578,70 +583,42 @@ void GLGizmoPainterBase::on_load(cereal::BinaryInputArchive&) void TriangleSelectorGUI::render(ImGuiWrapper* imgui) { - int enf_cnt = 0; - int blc_cnt = 0; - int seed_fill_cnt = 0; + static constexpr std::array enforcers_color{0.47f, 0.47f, 1.f, 1.f}; + static constexpr std::array blockers_color{1.f, 0.44f, 0.44f, 1.f}; - m_iva_enforcers.release_geometry(); - m_iva_blockers.release_geometry(); - m_iva_seed_fill.release_geometry(); + int enf_cnt = 0; + int blc_cnt = 0; + + for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) + iva->release_geometry(); for (const Triangle& tr : m_triangles) { - if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE || tr.is_selected_by_seed_fill()) + if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE) continue; - GLIndexedVertexArray& va = tr.get_state() == EnforcerBlockerType::ENFORCER - ? m_iva_enforcers - : m_iva_blockers; - int& cnt = tr.get_state() == EnforcerBlockerType::ENFORCER - ? enf_cnt - : blc_cnt; + GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; + int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; - for (int i=0; i<3; ++i) - va.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); - va.push_triangle(cnt, cnt + 1, cnt + 2); + for (int i = 0; i < 3; ++i) + iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); + iva.push_triangle(cnt, cnt + 1, cnt + 2); cnt += 3; } - for (const Triangle &tr : m_triangles) { - if (!tr.valid() || tr.is_split() || !tr.is_selected_by_seed_fill()) - continue; - - for (int i = 0; i < 3; ++i) - m_iva_seed_fill.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); - m_iva_seed_fill.push_triangle(seed_fill_cnt, seed_fill_cnt + 1, seed_fill_cnt + 2); - seed_fill_cnt += 3; - } - - m_iva_enforcers.finalize_geometry(true); - m_iva_blockers.finalize_geometry(true); - m_iva_seed_fill.finalize_geometry(true); - - bool render_enf = m_iva_enforcers.has_VBOs(); - bool render_blc = m_iva_blockers.has_VBOs(); - bool render_seed_fill = m_iva_seed_fill.has_VBOs(); + for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) + iva->finalize_geometry(true); auto* shader = wxGetApp().get_current_shader(); if (! shader) return; assert(shader->get_name() == "gouraud"); - if (render_enf) { - std::array color = { 0.47f, 0.47f, 1.f, 1.f }; - shader->set_uniform("uniform_color", color); - m_iva_enforcers.render(); - } - - if (render_blc) { - std::array color = { 1.f, 0.44f, 0.44f, 1.f }; - shader->set_uniform("uniform_color", color); - m_iva_blockers.render(); - } - - if (render_seed_fill) { - std::array color = { 0.f, 1.00f, 0.44f, 1.f }; - shader->set_uniform("uniform_color", color); - m_iva_seed_fill.render(); + for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), + std::make_pair(&m_iva_blockers, blockers_color)}) { + if (iva.first->has_VBOs()) { + shader->set_uniform("uniform_color", iva.second); + iva.first->render(); + } } @@ -746,5 +723,4 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) -} // namespace GUI -} // namespace Slic3r +} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 8e2d05ea8..b64585e9f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -31,10 +31,12 @@ class TriangleSelectorGUI : public TriangleSelector { public: explicit TriangleSelectorGUI(const TriangleMesh& mesh) : TriangleSelector(mesh) {} + virtual ~TriangleSelectorGUI() = default; // Render current selection. Transformation matrices are supposed // to be already set. - virtual void render(ImGuiWrapper* imgui = nullptr); + virtual void render(ImGuiWrapper *imgui); + void render() { this->render(nullptr); } #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void render_debug(ImGuiWrapper* imgui); @@ -43,11 +45,9 @@ public: #endif private: - GLIndexedVertexArray m_iva_enforcers; - GLIndexedVertexArray m_iva_blockers; + GLIndexedVertexArray m_iva_enforcers; + GLIndexedVertexArray m_iva_blockers; std::array m_varrays; -protected: - GLIndexedVertexArray m_iva_seed_fill; }; @@ -59,12 +59,12 @@ class GLGizmoPainterBase : public GLGizmoBase private: ObjectID m_old_mo_id; size_t m_old_volumes_size = 0; - virtual void on_render() const override {} - virtual void on_render_for_picking() const override {} + void on_render() const override {} + void on_render_for_picking() const override {} public: GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - ~GLGizmoPainterBase() override {} + ~GLGizmoPainterBase() override = default; virtual void set_painter_gizmo_data(const Selection& selection); virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); @@ -75,14 +75,13 @@ public: virtual void render_painter_gizmo() const = 0; protected: - void render_triangles(const Selection& selection) const; + void render_triangles(const Selection& selection, const bool use_polygon_offset_fill = true) const; void render_cursor() const; void render_cursor_circle() const; void render_cursor_sphere(const Transform3d& trafo) const; virtual void update_model_object() const = 0; virtual void update_from_model_object() = 0; void activate_internal_undo_redo_stack(bool activate); - void set_cursor_type(TriangleSelector::CursorType); virtual std::array get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; } virtual std::array get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; } @@ -104,6 +103,10 @@ protected: bool m_seed_fill_enabled = false; float m_seed_fill_angle = 0.f; + // It stores the value of the previous mesh_id to which the seed fill was applied. + // It is used to detect when the mouse has moved from one volume to another one. + int m_seed_fill_last_mesh_id = -1; + enum class Button { None, Left, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 7a274c927..d3c0c7d04 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -86,10 +86,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); - float caption_max = 0.f; - float total_text_max = 0.; - for (const std::string& t : {"enforce", "block", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); + float caption_max = 0.f; + float total_text_max = 0.f; + for (const auto &t : std::array{"enforce", "block", "remove"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); } caption_max += m_imgui->scaled(1.f); @@ -107,7 +107,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(text); }; - for (const std::string& t : {"enforce", "block", "remove"}) + for (const auto &t : std::array{"enforce", "block", "remove"}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); m_imgui->text(""); diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index f703ddcdb..482de650d 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -62,9 +62,10 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_type(itInfo), m_extruder(wxEmptyString) { - m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") - : info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") - : _L("Variable layer height"); + m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") : + info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") : + info_type == InfoItemType::MmuSegmentation ? _L("Paint-on segmentation") : + _L("Variable layer height"); m_info_item_type = info_type; } diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index 11a9225ca..a858b2619 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -50,6 +50,7 @@ enum class InfoItemType Undef, CustomSupports, CustomSeam, + MmuSegmentation, VariableLayerHeight };