Animation: Weight Paint select more/less for faces #105607

Merged
Christoph Lendenfeld merged 13 commits from ChrisLend/blender:weight_paint_grow_sel_face into main 2023-03-31 14:53:12 +02:00
7 changed files with 79 additions and 0 deletions
Showing only changes of commit 73ea99d29d - Show all commits

View File

@ -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

View File

@ -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")

View File

@ -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);

View File

@ -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)

Canonical variable name for the edges of a face is poly_edges

Canonical variable name for the edges of a face is `poly_edges`
{
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<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", ATTR_DOMAIN_FACE);
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", ATTR_DOMAIN_POINT);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
const Span<MEdge> edges = mesh->edges();
Vector<int> 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;

This is feeling a bit picky, sorry about that, but might as well extract this check for the poly instead of using a break like below (poly_has_unselected_neighbour) I think it makes sense for them to be consistent anyway.

This is feeling a bit picky, sorry about that, but might as well extract this check for the poly instead of using a `break` like below (`poly_has_unselected_neighbour`) I think it makes sense for them to be consistent anyway.
break;
}
}
}
select_poly.finish();
select_vert.finish();
paintface_flush_flags(C, ob, true, false);
}

The condition can be avoided by doing something like:

const bool has_selected_neighbour = poly_has_selected_neighbor(...);
select_poly.span[i] |= has_selected_neighbour;

Not sure if it's worth it though, you choose @ChrisLend. Could be applied below as well.

The condition can be avoided by doing something like: ```cpp const bool has_selected_neighbour = poly_has_selected_neighbor(...); select_poly.span[i] |= has_selected_neighbour; ``` Not sure if it's worth it though, you choose @ChrisLend. Could be applied below as well.

had a look at it but I think it's a bit clearer if the bool is set explicitly so I left it as is

had a look at it but I think it's a bit clearer if the bool is set explicitly so I left it as is
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)

Blender uses American English spelling, so neighbor instead of neighbor

Blender uses American English spelling, so `neighbor` instead of `neighbor`

thanks, that always gets me

thanks, that always gets me
{
using namespace blender;

View File

@ -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);

View File

@ -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);

View File

@ -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);