From a1e50cfe6b4dbc360b6118c63a0dc7445023c37b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 23 Dec 2019 12:46:05 +0300 Subject: Weight Paint: add a pie menu for locking and unlocking vertex groups. Provide different options for locking and unlocking vertex groups using bone selection, accessible via a pie menu triggered via the 'K' hotkey. To implement a variety of operations, extend the old operator with a new option to mask it by bone selection. If the X Mirror option is enabled, selection is automatically mirrored. This follows D6533 as the next step in improving accessibility of vertex group locking during weight painting. Differential Revision: https://developer.blender.org/D6618 --- source/blender/editors/object/object_vgroup.c | 163 +++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 5 deletions(-) (limited to 'source/blender/editors/object/object_vgroup.c') diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 9ccbc7a1a0a..17cc266b9c8 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -47,6 +47,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_deform.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_editmesh.h" @@ -1687,13 +1688,78 @@ static const EnumPropertyItem vgroup_lock_actions[] = { {0, NULL, 0, NULL, NULL}, }; -static void vgroup_lock_all(Object *ob, int action) +enum { + VGROUP_MASK_ALL, + VGROUP_MASK_SELECTED, + VGROUP_MASK_UNSELECTED, + VGROUP_MASK_INVERT_UNSELECTED, +}; + +static const EnumPropertyItem vgroup_lock_mask[] = { + {VGROUP_MASK_ALL, "ALL", 0, "All", "Apply action to all vertex groups"}, + {VGROUP_MASK_SELECTED, "SELECTED", 0, "Selected", "Apply to selected vertex groups"}, + {VGROUP_MASK_UNSELECTED, "UNSELECTED", 0, "Unselected", "Apply to unselected vertex groups"}, + {VGROUP_MASK_INVERT_UNSELECTED, + "INVERT_UNSELECTED", + 0, + "Invert Unselected", + "Apply the opposite of Lock/Unlock to unselected vertex groups"}, + {0, NULL, 0, NULL, NULL}, +}; + +static bool *vgroup_selected_get(Object *ob) +{ + int sel_count = 0, defbase_tot = BLI_listbase_count(&ob->defbase); + bool *mask; + + if (ob->mode & OB_MODE_WEIGHT_PAINT) { + mask = BKE_object_defgroup_selected_get(ob, defbase_tot, &sel_count); + + /* Mirror the selection if X Mirror is enabled. */ + Mesh *me = BKE_mesh_from_object(ob); + + if (me && (me->editflag & ME_EDIT_MIRROR_X) != 0) { + BKE_object_defgroup_mirror_selection(ob, defbase_tot, mask, mask, &sel_count); + } + } + else { + mask = MEM_callocN(defbase_tot * sizeof(bool), __func__); + } + + if (sel_count == 0 && ob->actdef >= 1 && ob->actdef <= defbase_tot) { + mask[ob->actdef - 1] = true; + } + + return mask; +} + +static void vgroup_lock_all(Object *ob, int action, int mask) { bDeformGroup *dg; + bool *selected = NULL; + int i; + + if (mask != VGROUP_MASK_ALL) { + selected = vgroup_selected_get(ob); + } if (action == VGROUP_TOGGLE) { action = VGROUP_LOCK; - for (dg = ob->defbase.first; dg; dg = dg->next) { + + for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { + switch (mask) { + case VGROUP_MASK_INVERT_UNSELECTED: + case VGROUP_MASK_SELECTED: + if (!selected[i]) + continue; + break; + case VGROUP_MASK_UNSELECTED: + if (selected[i]) + continue; + break; + default:; + } + if (dg->flag & DG_LOCK_WEIGHT) { action = VGROUP_UNLOCK; break; @@ -1701,7 +1767,19 @@ static void vgroup_lock_all(Object *ob, int action) } } - for (dg = ob->defbase.first; dg; dg = dg->next) { + for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { + switch (mask) { + case VGROUP_MASK_SELECTED: + if (!selected[i]) + continue; + break; + case VGROUP_MASK_UNSELECTED: + if (selected[i]) + continue; + break; + default:; + } + switch (action) { case VGROUP_LOCK: dg->flag |= DG_LOCK_WEIGHT; @@ -1713,6 +1791,14 @@ static void vgroup_lock_all(Object *ob, int action) dg->flag ^= DG_LOCK_WEIGHT; break; } + + if (mask == VGROUP_MASK_INVERT_UNSELECTED && !selected[i]) { + dg->flag ^= DG_LOCK_WEIGHT; + } + } + + if (selected) { + MEM_freeN(selected); } } @@ -3176,24 +3262,84 @@ static int vertex_group_lock_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); int action = RNA_enum_get(op->ptr, "action"); + int mask = RNA_enum_get(op->ptr, "mask"); - vgroup_lock_all(ob, action); + vgroup_lock_all(ob, action, mask); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; } +static char *vertex_group_lock_description(struct bContext *UNUSED(C), + struct wmOperatorType *UNUSED(op), + struct PointerRNA *params) +{ + int action = RNA_enum_get(params, "action"); + int mask = RNA_enum_get(params, "mask"); + + const char *action_str, *target_str; + + switch (action) { + case VGROUP_LOCK: + action_str = "Lock"; + break; + case VGROUP_UNLOCK: + action_str = "Unlock"; + break; + case VGROUP_TOGGLE: + action_str = "Toggle locks of"; + break; + case VGROUP_INVERT: + action_str = "Invert locks of"; + break; + default: + return NULL; + } + + switch (mask) { + case VGROUP_MASK_ALL: + target_str = "all"; + break; + case VGROUP_MASK_SELECTED: + target_str = "selected"; + break; + case VGROUP_MASK_UNSELECTED: + target_str = "unselected"; + break; + case VGROUP_MASK_INVERT_UNSELECTED: + switch (action) { + case VGROUP_INVERT: + target_str = "selected"; + break; + case VGROUP_LOCK: + target_str = "selected and unlock unselected"; + break; + case VGROUP_UNLOCK: + target_str = "selected and lock unselected"; + break; + default: + target_str = "all and invert unselected"; + } + break; + default: + return NULL; + } + + return BLI_sprintfN("%s %s vertex groups of the active object", action_str, target_str); +} + void OBJECT_OT_vertex_group_lock(wmOperatorType *ot) { /* identifiers */ ot->name = "Change the Lock On Vertex Groups"; ot->idname = "OBJECT_OT_vertex_group_lock"; - ot->description = "Change the lock state of all vertex groups of active object"; + ot->description = "Change the lock state of all or some vertex groups of active object"; /* api callbacks */ ot->poll = vertex_group_poll; ot->exec = vertex_group_lock_exec; + ot->get_description = vertex_group_lock_description; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3204,6 +3350,13 @@ void OBJECT_OT_vertex_group_lock(wmOperatorType *ot) VGROUP_TOGGLE, "Action", "Lock action to execute on vertex groups"); + + RNA_def_enum(ot->srna, + "mask", + vgroup_lock_mask, + VGROUP_MASK_ALL, + "Mask", + "Apply the action based on vertex group selection"); } static int vertex_group_invert_exec(bContext *C, wmOperator *op) -- cgit v1.2.3