From 73ea99d29d5ed6d48b7aac411db4c5fca98f135d Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 9 Mar 2023 14:56:56 +0100 Subject: [PATCH 01/10] implement select more operator --- .../keyconfig/keymap_data/blender_default.py | 1 + scripts/startup/bl_ui/space_view3d.py | 2 + source/blender/editors/include/ED_mesh.h | 4 ++ source/blender/editors/mesh/editface.cc | 46 +++++++++++++++++++ .../editors/sculpt_paint/paint_intern.h | 1 + .../blender/editors/sculpt_paint/paint_ops.cc | 1 + .../editors/sculpt_paint/paint_utils.c | 24 ++++++++++ 7 files changed, 79 insertions(+) diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index 96e5bef6078..ea0e51ef431 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4410,6 +4410,7 @@ def km_face_mask(params): {"properties": [("deselect", False)]}), ("paint.face_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True}, {"properties": [("deselect", True)]}), + ("paint.face_select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), ]) return keymap diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index ef3431fbe0a..df85a28117e 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -2011,6 +2011,8 @@ class VIEW3D_MT_select_paint_mask(Menu): layout.operator("paint.face_select_all", text="None").action = 'DESELECT' layout.operator("paint.face_select_all", text="Invert").action = 'INVERT' + layout.operator("paint.face_select_more") + layout.separator() layout.operator("view3d.select_box") diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 531fc03f285..8aa5435c162 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -419,6 +419,10 @@ void paintface_select_linked(struct bContext *C, struct Object *ob, const int mval[2], bool select); +/** Grow the selection of faces. + * \param face_step If true will also select faces that only touch on the corner. + */ +void paintface_select_more(struct bContext *C, struct Object *ob, bool face_step); bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]); void paintface_hide(struct bContext *C, struct Object *ob, bool unselected); diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 27d0c6808c8..522888d94ae 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -350,6 +350,52 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b paintface_flush_flags(C, ob, true, false); } +void paintface_select_more(bContext *C, Object *ob, const bool face_step) +{ + using namespace blender; + Mesh *mesh = BKE_mesh_from_object(ob); + if (mesh == nullptr || mesh->totpoly == 0) { + return; + } + + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); + bke::SpanAttributeWriter select_poly = attributes.lookup_or_add_for_write_span( + ".select_poly", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter select_vert = attributes.lookup_or_add_for_write_span( + ".select_vert", ATTR_DOMAIN_POINT); + const VArray hide_poly = attributes.lookup_or_default( + ".hide_poly", ATTR_DOMAIN_FACE, false); + + const Span polys = mesh->polys(); + const Span loops = mesh->loops(); + const Span edges = mesh->edges(); + + Vector indices; + + for (const int i : select_poly.span.index_range()) { + if (select_poly.span[i] || hide_poly[i]) { + continue; + } + const MPoly &poly = polys[i]; + + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const MEdge &edge = edges[loop.e]; + if (face_step && (select_vert.span[edge.v1] || select_vert.span[edge.v2])) { + select_poly.span[i] = true; + break; + } + else if (select_vert.span[edge.v1] && select_vert.span[edge.v2]) { + select_poly.span[i] = true; + break; + } + } + } + + select_poly.finish(); + select_vert.finish(); + paintface_flush_flags(C, ob, true, false); +} + bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags) { using namespace blender; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index cdf1256a097..51128f31065 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -378,6 +378,7 @@ void BRUSH_OT_sculpt_curves_falloff_preset(struct wmOperatorType *ot); void PAINT_OT_face_select_linked(struct wmOperatorType *ot); void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot); void PAINT_OT_face_select_all(struct wmOperatorType *ot); +void PAINT_OT_face_select_more(struct wmOperatorType *ot); void PAINT_OT_face_select_hide(struct wmOperatorType *ot); void PAINT_OT_face_vert_reveal(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.cc b/source/blender/editors/sculpt_paint/paint_ops.cc index ca102b5a0b8..a1ea615cb3a 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_ops.cc @@ -1518,6 +1518,7 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_face_select_linked); WM_operatortype_append(PAINT_OT_face_select_linked_pick); WM_operatortype_append(PAINT_OT_face_select_all); + WM_operatortype_append(PAINT_OT_face_select_more); WM_operatortype_append(PAINT_OT_face_select_hide); WM_operatortype_append(PAINT_OT_face_vert_reveal); diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 4953ab84687..5a1270a8e99 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -693,6 +693,30 @@ void PAINT_OT_face_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } +/* face-select ops */ +static int paint_select_more_exec(bContext *C, wmOperator *op) +{ + const bool face_step = RNA_boolean_get(op->ptr, "face_step"); + paintface_select_more(C, CTX_data_active_object(C), face_step); + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; +} + +void PAINT_OT_face_select_more(wmOperatorType *ot) +{ + ot->name = "Select More"; + ot->description = "Select Faces connected to existing selection"; + ot->idname = "PAINT_OT_face_select_more"; + + ot->exec = paint_select_more_exec; + ot->poll = facemask_paint_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean( + ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner"); +} + static int vert_select_all_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); -- 2.30.2 From c91d16b4cdb0f4132147c53623b60d52db3282f4 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 9 Mar 2023 16:22:04 +0100 Subject: [PATCH 02/10] implement select less operator --- .../keyconfig/keymap_data/blender_default.py | 1 + scripts/startup/bl_ui/space_view3d.py | 1 + source/blender/editors/include/ED_mesh.h | 1 + source/blender/editors/mesh/editface.cc | 74 +++++++++++++++++-- .../editors/sculpt_paint/paint_intern.h | 1 + .../blender/editors/sculpt_paint/paint_ops.cc | 1 + .../editors/sculpt_paint/paint_utils.c | 24 +++++- 7 files changed, 96 insertions(+), 7 deletions(-) diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index ea0e51ef431..505d795f4c3 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4411,6 +4411,7 @@ def km_face_mask(params): ("paint.face_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True}, {"properties": [("deselect", True)]}), ("paint.face_select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("paint.face_select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), ]) return keymap diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index df85a28117e..ac241895b7a 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -2012,6 +2012,7 @@ class VIEW3D_MT_select_paint_mask(Menu): layout.operator("paint.face_select_all", text="Invert").action = 'INVERT' layout.operator("paint.face_select_more") + layout.operator("paint.face_select_less") layout.separator() diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 8aa5435c162..0bf06820bd7 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -423,6 +423,7 @@ void paintface_select_linked(struct bContext *C, * \param face_step If true will also select faces that only touch on the corner. */ void paintface_select_more(struct bContext *C, struct Object *ob, bool face_step); +void paintface_select_less(struct bContext *C, struct Object *ob, bool face_step); bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]); void paintface_hide(struct bContext *C, struct Object *ob, bool unselected); diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 522888d94ae..cb186737552 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -370,8 +370,6 @@ void paintface_select_more(bContext *C, Object *ob, const bool face_step) const Span loops = mesh->loops(); const Span edges = mesh->edges(); - Vector indices; - for (const int i : select_poly.span.index_range()) { if (select_poly.span[i] || hide_poly[i]) { continue; @@ -380,11 +378,16 @@ void paintface_select_more(bContext *C, Object *ob, const bool face_step) for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { const MEdge &edge = edges[loop.e]; - if (face_step && (select_vert.span[edge.v1] || select_vert.span[edge.v2])) { - select_poly.span[i] = true; - break; + /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces + * will have some vertices selected. */ + bool selected_neighbor = false; + if (face_step) { + selected_neighbor = select_vert.span[edge.v1] || select_vert.span[edge.v2]; } - else if (select_vert.span[edge.v1] && select_vert.span[edge.v2]) { + else { + selected_neighbor = select_vert.span[edge.v1] && select_vert.span[edge.v2]; + } + if (selected_neighbor) { select_poly.span[i] = true; break; } @@ -396,6 +399,65 @@ void paintface_select_more(bContext *C, Object *ob, const bool face_step) paintface_flush_flags(C, ob, true, false); } +void paintface_select_less(bContext *C, Object *ob, const bool face_step) +{ + using namespace blender; + Mesh *mesh = BKE_mesh_from_object(ob); + if (mesh == nullptr || mesh->totpoly == 0) { + return; + } + + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); + bke::SpanAttributeWriter select_poly = attributes.lookup_or_add_for_write_span( + ".select_poly", ATTR_DOMAIN_FACE); + const VArray hide_poly = attributes.lookup_or_default( + ".hide_poly", ATTR_DOMAIN_FACE, false); + + const Span polys = mesh->polys(); + const Span loops = mesh->loops(); + const Span edges = mesh->edges(); + + std::vector verts_of_unselected_faces(mesh->totvert, false); + + /* Find all vertices of unselected faces to help find neighboring faces after. */ + for (const int i : select_poly.span.index_range()) { + if (select_poly.span[i]) { + continue; + } + const MPoly &poly = polys[i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + verts_of_unselected_faces[loop.v] = true; + } + } + + for (const int i : select_poly.span.index_range()) { + if (!select_poly.span[i] || hide_poly[i]) { + continue; + } + const MPoly &poly = polys[i]; + + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const MEdge &edge = edges[loop.e]; + bool unselected_neighbor = false; + if (face_step) { + unselected_neighbor = verts_of_unselected_faces[edge.v1] || + verts_of_unselected_faces[edge.v2]; + } + else { + unselected_neighbor = verts_of_unselected_faces[edge.v1] && + verts_of_unselected_faces[edge.v2]; + } + if (unselected_neighbor) { + select_poly.span[i] = false; + break; + } + } + } + + select_poly.finish(); + paintface_flush_flags(C, ob, true, false); +} + bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags) { using namespace blender; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 51128f31065..9b7c404d40f 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -379,6 +379,7 @@ void PAINT_OT_face_select_linked(struct wmOperatorType *ot); void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot); void PAINT_OT_face_select_all(struct wmOperatorType *ot); void PAINT_OT_face_select_more(struct wmOperatorType *ot); +void PAINT_OT_face_select_less(struct wmOperatorType *ot); void PAINT_OT_face_select_hide(struct wmOperatorType *ot); void PAINT_OT_face_vert_reveal(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.cc b/source/blender/editors/sculpt_paint/paint_ops.cc index a1ea615cb3a..03d8b7cdb8d 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_ops.cc @@ -1519,6 +1519,7 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_face_select_linked_pick); WM_operatortype_append(PAINT_OT_face_select_all); WM_operatortype_append(PAINT_OT_face_select_more); + WM_operatortype_append(PAINT_OT_face_select_less); WM_operatortype_append(PAINT_OT_face_select_hide); WM_operatortype_append(PAINT_OT_face_vert_reveal); diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 5a1270a8e99..1e06080fd80 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -693,7 +693,6 @@ void PAINT_OT_face_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* face-select ops */ static int paint_select_more_exec(bContext *C, wmOperator *op) { const bool face_step = RNA_boolean_get(op->ptr, "face_step"); @@ -717,6 +716,29 @@ void PAINT_OT_face_select_more(wmOperatorType *ot) ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner"); } +static int paint_select_less_exec(bContext *C, wmOperator *op) +{ + const bool face_step = RNA_boolean_get(op->ptr, "face_step"); + paintface_select_less(C, CTX_data_active_object(C), face_step); + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; +} + +void PAINT_OT_face_select_less(wmOperatorType *ot) +{ + ot->name = "Select Less"; + ot->description = "Deselect Faces connected to existing selection"; + ot->idname = "PAINT_OT_face_select_less"; + + ot->exec = paint_select_less_exec; + ot->poll = facemask_paint_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean( + ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner"); +} + static int vert_select_all_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); -- 2.30.2 From ad7e632371cb2949db057cc547327b6d3d4156e6 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 9 Mar 2023 16:28:20 +0100 Subject: [PATCH 03/10] add threading --- source/blender/editors/mesh/editface.cc | 84 +++++++++++++------------ 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index cb186737552..e27b7412043 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -370,29 +370,31 @@ void paintface_select_more(bContext *C, Object *ob, const bool face_step) const Span loops = mesh->loops(); const Span edges = mesh->edges(); - for (const int i : select_poly.span.index_range()) { - if (select_poly.span[i] || hide_poly[i]) { - continue; - } - const MPoly &poly = polys[i]; + threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) { + for (const int i : range) { + if (select_poly.span[i] || hide_poly[i]) { + continue; + } + const MPoly &poly = polys[i]; - for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - const MEdge &edge = edges[loop.e]; - /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces - * will have some vertices selected. */ - bool selected_neighbor = false; - if (face_step) { - selected_neighbor = select_vert.span[edge.v1] || select_vert.span[edge.v2]; - } - else { - selected_neighbor = select_vert.span[edge.v1] && select_vert.span[edge.v2]; - } - if (selected_neighbor) { - select_poly.span[i] = true; - break; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const MEdge &edge = edges[loop.e]; + /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces + * will have some vertices selected. */ + bool selected_neighbor = false; + if (face_step) { + selected_neighbor = select_vert.span[edge.v1] || select_vert.span[edge.v2]; + } + else { + selected_neighbor = select_vert.span[edge.v1] && select_vert.span[edge.v2]; + } + if (selected_neighbor) { + select_poly.span[i] = true; + break; + } } } - } + }); select_poly.finish(); select_vert.finish(); @@ -430,29 +432,31 @@ void paintface_select_less(bContext *C, Object *ob, const bool face_step) } } - for (const int i : select_poly.span.index_range()) { - if (!select_poly.span[i] || hide_poly[i]) { - continue; - } - const MPoly &poly = polys[i]; + threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) { + for (const int i : range) { + if (!select_poly.span[i] || hide_poly[i]) { + continue; + } + const MPoly &poly = polys[i]; - for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - const MEdge &edge = edges[loop.e]; - bool unselected_neighbor = false; - if (face_step) { - unselected_neighbor = verts_of_unselected_faces[edge.v1] || - verts_of_unselected_faces[edge.v2]; - } - else { - unselected_neighbor = verts_of_unselected_faces[edge.v1] && - verts_of_unselected_faces[edge.v2]; - } - if (unselected_neighbor) { - select_poly.span[i] = false; - break; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const MEdge &edge = edges[loop.e]; + bool unselected_neighbor = false; + if (face_step) { + unselected_neighbor = verts_of_unselected_faces[edge.v1] || + verts_of_unselected_faces[edge.v2]; + } + else { + unselected_neighbor = verts_of_unselected_faces[edge.v1] && + verts_of_unselected_faces[edge.v2]; + } + if (unselected_neighbor) { + select_poly.span[i] = false; + break; + } } } - } + }); select_poly.finish(); paintface_flush_flags(C, ob, true, false); -- 2.30.2 From 158d68471e9d5546f2edc8b204eba86ddf415d9c Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 16 Mar 2023 10:58:27 +0100 Subject: [PATCH 04/10] implement hans' feedback --- source/blender/editors/mesh/editface.cc | 49 +++++++++++++++---------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 11c3a05a808..a55f28c7d8b 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -401,6 +401,30 @@ void paintface_select_more(bContext *C, Object *ob, const bool face_step) paintface_flush_flags(C, ob, true, false); } +static bool poly_has_unselected_neighbour(const MPoly &poly, + blender::Span poly_loops, + blender::Span edges, + blender::BitVector<> &verts_of_unselected_faces, + const bool face_step) +{ + for (const MLoop &loop : poly_loops.slice(poly.loopstart, poly.totloop)) { + const MEdge &edge = edges[loop.e]; + bool unselected_neighbor = false; + if (face_step) { + unselected_neighbor = verts_of_unselected_faces[edge.v1].test() || + verts_of_unselected_faces[edge.v2].test(); + } + else { + unselected_neighbor = verts_of_unselected_faces[edge.v1].test() && + verts_of_unselected_faces[edge.v2].test(); + } + if (unselected_neighbor) { + return true; + } + } + return false; +} + void paintface_select_less(bContext *C, Object *ob, const bool face_step) { using namespace blender; @@ -419,7 +443,7 @@ void paintface_select_less(bContext *C, Object *ob, const bool face_step) const Span loops = mesh->loops(); const Span edges = mesh->edges(); - std::vector verts_of_unselected_faces(mesh->totvert, false); + BitVector<> verts_of_unselected_faces(mesh->totvert, false); /* Find all vertices of unselected faces to help find neighboring faces after. */ for (const int i : select_poly.span.index_range()) { @@ -428,32 +452,19 @@ void paintface_select_less(bContext *C, Object *ob, const bool face_step) } const MPoly &poly = polys[i]; for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - verts_of_unselected_faces[loop.v] = true; + verts_of_unselected_faces[loop.v].set(true); } } - threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) { + threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { for (const int i : range) { if (!select_poly.span[i] || hide_poly[i]) { continue; } const MPoly &poly = polys[i]; - - for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - const MEdge &edge = edges[loop.e]; - bool unselected_neighbor = false; - if (face_step) { - unselected_neighbor = verts_of_unselected_faces[edge.v1] || - verts_of_unselected_faces[edge.v2]; - } - else { - unselected_neighbor = verts_of_unselected_faces[edge.v1] && - verts_of_unselected_faces[edge.v2]; - } - if (unselected_neighbor) { - select_poly.span[i] = false; - break; - } + if (poly_has_unselected_neighbour( + poly, loops, edges, verts_of_unselected_faces, face_step)) { + select_poly.span[i] = false; } } }); -- 2.30.2 From 24aee56b7fa21b064a6009fadd526161c0d69947 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 23 Mar 2023 10:54:15 +0100 Subject: [PATCH 05/10] implement hans' feedback --- source/blender/editors/include/ED_mesh.h | 4 +- source/blender/editors/mesh/editface.cc | 43 +++++++------------ .../editors/sculpt_paint/paint_utils.c | 20 ++++++++- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 0bf06820bd7..6d71536c31a 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -422,8 +422,8 @@ void paintface_select_linked(struct bContext *C, /** Grow the selection of faces. * \param face_step If true will also select faces that only touch on the corner. */ -void paintface_select_more(struct bContext *C, struct Object *ob, bool face_step); -void paintface_select_less(struct bContext *C, struct Object *ob, bool face_step); +void paintface_select_more(struct Mesh *mesh, bool face_step); +void paintface_select_less(struct Mesh *mesh, bool face_step); bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]); void paintface_hide(struct bContext *C, struct Object *ob, bool unselected); diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index a55f28c7d8b..0f1d99cb9f1 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -350,13 +350,9 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b paintface_flush_flags(C, ob, true, false); } -void paintface_select_more(bContext *C, Object *ob, const bool face_step) +void paintface_select_more(Mesh *mesh, const bool face_step) { using namespace blender; - Mesh *mesh = BKE_mesh_from_object(ob); - if (mesh == nullptr || mesh->totpoly == 0) { - return; - } bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); bke::SpanAttributeWriter select_poly = attributes.lookup_or_add_for_write_span( @@ -398,40 +394,32 @@ void paintface_select_more(bContext *C, Object *ob, const bool face_step) select_poly.finish(); select_vert.finish(); - paintface_flush_flags(C, ob, true, false); } -static bool poly_has_unselected_neighbour(const MPoly &poly, - blender::Span poly_loops, +static bool poly_has_unselected_neighbour(blender::Span poly_loops, blender::Span edges, - blender::BitVector<> &verts_of_unselected_faces, + blender::BitSpan verts_of_unselected_faces, const bool face_step) { - for (const MLoop &loop : poly_loops.slice(poly.loopstart, poly.totloop)) { + for (const MLoop &loop : poly_loops) { const MEdge &edge = edges[loop.e]; - bool unselected_neighbor = false; if (face_step) { - unselected_neighbor = verts_of_unselected_faces[edge.v1].test() || - verts_of_unselected_faces[edge.v2].test(); + if (verts_of_unselected_faces[edge.v1] || verts_of_unselected_faces[edge.v2]) { + return true; + } } else { - unselected_neighbor = verts_of_unselected_faces[edge.v1].test() && - verts_of_unselected_faces[edge.v2].test(); - } - if (unselected_neighbor) { - return true; + if (verts_of_unselected_faces[edge.v1] && verts_of_unselected_faces[edge.v2]) { + return true; + } } } return false; } -void paintface_select_less(bContext *C, Object *ob, const bool face_step) +void paintface_select_less(Mesh *mesh, const bool face_step) { using namespace blender; - Mesh *mesh = BKE_mesh_from_object(ob); - if (mesh == nullptr || mesh->totpoly == 0) { - return; - } bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); bke::SpanAttributeWriter select_poly = attributes.lookup_or_add_for_write_span( @@ -446,7 +434,7 @@ void paintface_select_less(bContext *C, Object *ob, const bool face_step) BitVector<> verts_of_unselected_faces(mesh->totvert, false); /* Find all vertices of unselected faces to help find neighboring faces after. */ - for (const int i : select_poly.span.index_range()) { + for (const int i : polys.index_range()) { if (select_poly.span[i]) { continue; } @@ -462,15 +450,16 @@ void paintface_select_less(bContext *C, Object *ob, const bool face_step) continue; } const MPoly &poly = polys[i]; - if (poly_has_unselected_neighbour( - poly, loops, edges, verts_of_unselected_faces, face_step)) { + if (poly_has_unselected_neighbour(loops.slice(poly.loopstart, poly.totloop), + edges, + verts_of_unselected_faces, + face_step)) { select_poly.span[i] = false; } } }); select_poly.finish(); - paintface_flush_flags(C, ob, true, false); } bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags) diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 1e06080fd80..411b8cdfd64 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -695,8 +695,16 @@ void PAINT_OT_face_select_all(wmOperatorType *ot) static int paint_select_more_exec(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); + Mesh *mesh = BKE_mesh_from_object(ob); + if (mesh == NULL || mesh->totpoly == 0) { + return OPERATOR_CANCELLED; + } + const bool face_step = RNA_boolean_get(op->ptr, "face_step"); - paintface_select_more(C, CTX_data_active_object(C), face_step); + paintface_select_more(mesh, face_step); + paintface_flush_flags(C, ob, true, false); + ED_region_tag_redraw(CTX_wm_region(C)); return OPERATOR_FINISHED; } @@ -718,8 +726,16 @@ void PAINT_OT_face_select_more(wmOperatorType *ot) static int paint_select_less_exec(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); + Mesh *mesh = BKE_mesh_from_object(ob); + if (mesh == NULL || mesh->totpoly == 0) { + return OPERATOR_CANCELLED; + } + const bool face_step = RNA_boolean_get(op->ptr, "face_step"); - paintface_select_less(C, CTX_data_active_object(C), face_step); + paintface_select_less(mesh, face_step); + paintface_flush_flags(C, ob, true, false); + ED_region_tag_redraw(CTX_wm_region(C)); return OPERATOR_FINISHED; } -- 2.30.2 From e7f242e37461fd455854d60c77eaa453ee84e486 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 24 Mar 2023 14:09:19 +0100 Subject: [PATCH 06/10] implement changes after MLoop was removed --- source/blender/editors/mesh/editface.cc | 33 +++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 75d228fe777..cf4a34b4ea8 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -363,7 +363,7 @@ void paintface_select_more(Mesh *mesh, const bool face_step) ".hide_poly", ATTR_DOMAIN_FACE, false); const Span polys = mesh->polys(); - const Span loops = mesh->loops(); + const Span corner_edges = mesh->corner_edges(); const Span edges = mesh->edges(); threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) { @@ -373,8 +373,8 @@ void paintface_select_more(Mesh *mesh, const bool face_step) } const MPoly &poly = polys[i]; - for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - const MEdge &edge = edges[loop.e]; + for (const int edge_index : corner_edges.slice(poly.loopstart, poly.totloop)) { + const MEdge &edge = edges[edge_index]; /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces * will have some vertices selected. */ bool selected_neighbor = false; @@ -396,13 +396,13 @@ void paintface_select_more(Mesh *mesh, const bool face_step) select_vert.finish(); } -static bool poly_has_unselected_neighbour(blender::Span poly_loops, - blender::Span edges, - blender::BitSpan verts_of_unselected_faces, - const bool face_step) +static bool poly_has_unselected_neighbor(blender::Span edge_indices, + blender::Span edges, + blender::BitSpan verts_of_unselected_faces, + const bool face_step) { - for (const MLoop &loop : poly_loops) { - const MEdge &edge = edges[loop.e]; + for (const int edge_index : edge_indices) { + const MEdge &edge = edges[edge_index]; if (face_step) { if (verts_of_unselected_faces[edge.v1] || verts_of_unselected_faces[edge.v2]) { return true; @@ -428,7 +428,8 @@ void paintface_select_less(Mesh *mesh, const bool face_step) ".hide_poly", ATTR_DOMAIN_FACE, false); const Span polys = mesh->polys(); - const Span loops = mesh->loops(); + const Span corner_verts = mesh->corner_verts(); + const Span corner_edges = mesh->corner_edges(); const Span edges = mesh->edges(); BitVector<> verts_of_unselected_faces(mesh->totvert, false); @@ -439,8 +440,8 @@ void paintface_select_less(Mesh *mesh, const bool face_step) continue; } const MPoly &poly = polys[i]; - for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - verts_of_unselected_faces[loop.v].set(true); + for (const int vert_index : corner_verts.slice(poly.loopstart, poly.totloop)) { + verts_of_unselected_faces[vert_index].set(true); } } @@ -450,10 +451,10 @@ void paintface_select_less(Mesh *mesh, const bool face_step) continue; } const MPoly &poly = polys[i]; - if (poly_has_unselected_neighbour(loops.slice(poly.loopstart, poly.totloop), - edges, - verts_of_unselected_faces, - face_step)) { + if (poly_has_unselected_neighbor(corner_edges.slice(poly.loopstart, poly.totloop), + edges, + verts_of_unselected_faces, + face_step)) { select_poly.span[i] = false; } } -- 2.30.2 From d05334b691eccd5b7145674b249539ba57a6ced4 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 24 Mar 2023 14:28:35 +0100 Subject: [PATCH 07/10] extract function poly_has_selected_neighbor --- source/blender/editors/mesh/editface.cc | 44 ++++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index cf4a34b4ea8..58bbea7c335 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -350,6 +350,29 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b paintface_flush_flags(C, ob, true, false); } +static bool poly_has_selected_neighbor(blender::Span edge_indices, + blender::Span edges, + blender::Span select_vert, + const bool face_step) +{ + for (const int edge_index : edge_indices) { + const MEdge &edge = edges[edge_index]; + /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces + * will have some vertices selected. */ + if (face_step) { + if (select_vert[edge.v1] || select_vert[edge.v2]) { + return true; + } + } + else { + if (select_vert[edge.v1] && select_vert[edge.v2]) { + return true; + } + } + } + return false; +} + void paintface_select_more(Mesh *mesh, const bool face_step) { using namespace blender; @@ -372,22 +395,11 @@ void paintface_select_more(Mesh *mesh, const bool face_step) continue; } const MPoly &poly = polys[i]; - - for (const int edge_index : corner_edges.slice(poly.loopstart, poly.totloop)) { - const MEdge &edge = edges[edge_index]; - /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces - * will have some vertices selected. */ - bool selected_neighbor = false; - if (face_step) { - selected_neighbor = select_vert.span[edge.v1] || select_vert.span[edge.v2]; - } - else { - selected_neighbor = select_vert.span[edge.v1] && select_vert.span[edge.v2]; - } - if (selected_neighbor) { - select_poly.span[i] = true; - break; - } + if (poly_has_selected_neighbor(corner_edges.slice(poly.loopstart, poly.totloop), + edges, + select_vert.span, + face_step)) { + select_poly.span[i] = true; } } }); -- 2.30.2 From 40d0722deab8e6b23b02f35d803a829361cda4fc Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 24 Mar 2023 14:54:21 +0100 Subject: [PATCH 08/10] change edge_indices to poly_edges --- source/blender/editors/mesh/editface.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 58bbea7c335..80f12991542 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -350,12 +350,12 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b paintface_flush_flags(C, ob, true, false); } -static bool poly_has_selected_neighbor(blender::Span edge_indices, +static bool poly_has_selected_neighbor(blender::Span poly_edges, blender::Span edges, blender::Span select_vert, const bool face_step) { - for (const int edge_index : edge_indices) { + for (const int edge_index : poly_edges) { const MEdge &edge = edges[edge_index]; /* If a poly is selected, all of its verts are selected too, meaning that neighboring faces * will have some vertices selected. */ @@ -408,12 +408,12 @@ void paintface_select_more(Mesh *mesh, const bool face_step) select_vert.finish(); } -static bool poly_has_unselected_neighbor(blender::Span edge_indices, +static bool poly_has_unselected_neighbor(blender::Span poly_edges, blender::Span edges, blender::BitSpan verts_of_unselected_faces, const bool face_step) { - for (const int edge_index : edge_indices) { + for (const int edge_index : poly_edges) { const MEdge &edge = edges[edge_index]; if (face_step) { if (verts_of_unselected_faces[edge.v1] || verts_of_unselected_faces[edge.v2]) { -- 2.30.2 From 793b5d5e8fc9494bad8c9fe09189cceb58d322c0 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 24 Mar 2023 15:00:55 +0100 Subject: [PATCH 09/10] remove default false from BitVector --- source/blender/editors/mesh/editface.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 80f12991542..84dee4fd5e9 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -444,7 +444,7 @@ void paintface_select_less(Mesh *mesh, const bool face_step) const Span corner_edges = mesh->corner_edges(); const Span edges = mesh->edges(); - BitVector<> verts_of_unselected_faces(mesh->totvert, false); + BitVector<> verts_of_unselected_faces(mesh->totvert); /* Find all vertices of unselected faces to help find neighboring faces after. */ for (const int i : polys.index_range()) { -- 2.30.2 From f65e124d32d6f7a3ccbae85051496b7cce603d8b Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 24 Mar 2023 15:10:44 +0100 Subject: [PATCH 10/10] vert_index -> vert --- source/blender/editors/mesh/editface.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 84dee4fd5e9..c49db9f094e 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -452,8 +452,8 @@ void paintface_select_less(Mesh *mesh, const bool face_step) continue; } const MPoly &poly = polys[i]; - for (const int vert_index : corner_verts.slice(poly.loopstart, poly.totloop)) { - verts_of_unselected_faces[vert_index].set(true); + for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) { + verts_of_unselected_faces[vert].set(true); } } -- 2.30.2