Added polished Vertex Weights Panel (properties sidebar)

This commit is contained in:
Gaia Clary 2013-06-23 15:37:08 +00:00
parent 219f3ea85d
commit 70fd2320c8
10 changed files with 672 additions and 342 deletions

@ -65,6 +65,8 @@ float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup);
float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup);
void defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src);
void defvert_copy_subset(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
const bool *vgroup_subset, const int vgroup_tot);
void defvert_copy_index(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const int defgroup);
void defvert_sync(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const bool use_verify);
void defvert_sync_mapped(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
@ -73,6 +75,8 @@ void defvert_remap(struct MDeformVert *dvert, int *map, const int map_len);
void defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void defvert_normalize(struct MDeformVert *dvert);
void defvert_normalize_subset(struct MDeformVert *dvert,
const bool *vgroup_subset, const int vgroup_tot);
void defvert_normalize_lock_single(struct MDeformVert *dvert, const int def_nr_lock);
void defvert_normalize_lock_map(struct MDeformVert *dvert, const bool *lock_flags, const int defbase_tot);

@ -80,7 +80,21 @@ bDeformGroup *defgroup_duplicate(bDeformGroup *ingroup)
return outgroup;
}
/* copy & overwrite weights */
/* overwrite weights filtered by vgroup_subset
* - do nothing if neither are set.
* - add destination weight if needed
*/
void defvert_copy_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src,
const bool *vgroup_subset, const int vgroup_tot)
{
int defgroup;
for (defgroup=0; defgroup < vgroup_tot; defgroup++) {
if (vgroup_subset[defgroup]) {
defvert_copy_index(dvert_dst, dvert_src, defgroup);
}
}
}
void defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
{
if (dvert_dst->totweight == dvert_src->totweight) {
@ -181,6 +195,35 @@ void defvert_remap(MDeformVert *dvert, int *map, const int map_len)
}
}
/**
* Same as #defvert_normalize but takes a bool array.
*/
void defvert_normalize_subset(MDeformVert *dvert,
const bool *vgroup_subset, const int vgroup_tot)
{
MDeformWeight *dw;
unsigned int i;
float tot_weight = 0.0f;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
tot_weight += dw->weight;
}
}
if (tot_weight > 0.0f) {
float scalar = 1.0f / tot_weight;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
dw->weight *= scalar;
/* in case of division errors with very low weights */
CLAMP(dw->weight, 0.0f, 1.0f);
}
}
}
}
void defvert_normalize(MDeformVert *dvert)
{
if (dvert->totweight <= 0) {

@ -250,6 +250,7 @@ bool ED_vgroup_object_is_edit_mode(struct Object *ob);
void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode);
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
/* mesh_data.c */

@ -65,6 +65,11 @@ struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
struct wmOperatorType;
struct PointerRNA;
struct PropertyRNA;
struct EnumPropertyItem;
enum eVGroupSelect;
/* object_edit.c */
struct Object *ED_object_context(struct bContext *C); /* context.object */
@ -200,21 +205,16 @@ int ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v);
/* object_select.c */
void ED_object_select_linked_by_id(struct bContext *C, struct ID *id);
/* object_vgroup.c */
typedef enum eVGroupSelect {
WT_VGROUP_ACTIVE = 1,
WT_VGROUP_BONE_SELECT = 2,
WT_VGROUP_BONE_DEFORM = 3,
WT_VGROUP_ALL = 4,
} eVGroupSelect;
#define WT_VGROUP_MASK_ALL \
((1 << WT_VGROUP_ACTIVE) | \
(1 << WT_VGROUP_BONE_SELECT) | \
(1 << WT_VGROUP_BONE_DEFORM) | \
(1 << WT_VGROUP_ALL))
bool *ED_vgroup_subset_from_select_type(struct Object *ob, enum eVGroupSelect subset_type,
int *r_vgroup_tot, int *r_subset_count);
bool *ED_vgroup_subset_from_select_type(struct Object *ob, eVGroupSelect subset_type, int *r_vgroup_tot, int *r_subset_count);
struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
const struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int *free,
const unsigned int selection_mask);
#ifdef __cplusplus
}

@ -223,6 +223,11 @@ void OBJECT_OT_vertex_group_mirror(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_set_active(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_sort(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_move(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_paste(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_delete(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_set_active(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_normalize_active(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
/* object_shapekey.c */
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);

@ -195,6 +195,11 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_group_set_active);
WM_operatortype_append(OBJECT_OT_vertex_group_sort);
WM_operatortype_append(OBJECT_OT_vertex_group_move);
WM_operatortype_append(OBJECT_OT_vertex_weight_paste);
WM_operatortype_append(OBJECT_OT_vertex_weight_delete);
WM_operatortype_append(OBJECT_OT_vertex_weight_set_active);
WM_operatortype_append(OBJECT_OT_vertex_weight_normalize_active);
WM_operatortype_append(OBJECT_OT_vertex_weight_copy);
WM_operatortype_append(OBJECT_OT_game_property_new);
WM_operatortype_append(OBJECT_OT_game_property_remove);

@ -411,6 +411,239 @@ bool ED_vgroup_copy_array(Object *ob, Object *ob_from)
return true;
}
static MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
{
if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH && ob->defbase.first) {
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
if (cd_dvert_offset != -1) {
BMEditSelection *ese = (BMEditSelection *)em->bm->selected.last;
if (ese && ese->htype == BM_VERT) {
BMVert *eve = (BMVert *)ese->ele;
if (r_eve) *r_eve = eve;
return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
}
}
}
if (r_eve) *r_eve = NULL;
return NULL;
}
/* TODO, cache flip data to speedup calls within a loop. */
static void mesh_defvert_mirror_update_internal(Object *ob,
MDeformVert *dvert_dst, MDeformVert *dvert_src,
const int def_nr)
{
if (def_nr == -1) {
/* all vgroups, add groups where neded */
int flip_map_len;
int *flip_map = defgroup_flip_map(ob, &flip_map_len, true);
defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true);
MEM_freeN(flip_map);
}
else {
/* single vgroup */
MDeformWeight *dw = defvert_verify_index(dvert_dst, defgroup_flip_index(ob, def_nr, 1));
if (dw) {
dw->weight = defvert_find_weight(dvert_src, def_nr);
}
}
}
static MDeformVert *ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
{
Mesh *me = ob->data;
int index = BKE_mesh_mselect_active_get(me, ME_VSEL);
if (r_index) *r_index = index;
if (index == -1 || me->dvert == NULL) {
return NULL;
}
else {
return me->dvert + index;
}
}
static void ED_mesh_defvert_mirror_update_em(Object *ob, BMVert *eve, int def_nr, int vidx,
const int cd_dvert_offset)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
BMVert *eve_mirr;
eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx);
if (eve_mirr && eve_mirr != eve) {
MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
}
}
static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
{
int vidx_mirr;
Mesh *me = ob->data;
if (vidx == -1)
return;
vidx_mirr = mesh_get_x_mirror_vert(ob, vidx);
if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
MDeformVert *dvert_src = &me->dvert[vidx];
MDeformVert *dvert_dst = &me->dvert[vidx_mirr];
mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
}
}
static MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
{
if (ob->type == OB_MESH) {
if (ob->mode & OB_MODE_EDIT) {
return ED_mesh_active_dvert_get_em(ob, NULL);
}
else {
return ED_mesh_active_dvert_get_ob(ob, NULL);
}
}
else {
return NULL;
}
}
/**
* Use when adjusting the active vertex weight and apply to mirror vertices.
*/
void ED_vgroup_vert_active_mirror(Object *ob, int def_nr)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
MDeformVert *dvert_act;
if (me->editflag & ME_EDIT_MIRROR_X) {
if (em) {
BMVert *eve_act;
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
if (dvert_act) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
ED_mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset);
}
}
else {
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act) {
ED_mesh_defvert_mirror_update_ob(ob, def_nr, v_act);
}
}
}
}
static void vgroup_remove_weight(Object *ob, const int def_nr)
{
MDeformVert *dvert_act;
MDeformWeight *dw;
dvert_act = ED_mesh_active_dvert_get_only(ob);
dw = defvert_find_index(dvert_act, def_nr);
defvert_remove_group(dvert_act, dw);
}
static void vgroup_normalize_active(Object *ob, eVGroupSelect subset_type)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
BMVert *eve_act;
int v_act;
MDeformVert *dvert_act;
int subset_count, vgroup_tot;
const bool *vgroup_validmap;
if (em) {
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
}
else {
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
}
if (dvert_act == NULL) {
return;
}
vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot);
MEM_freeN((void *)vgroup_validmap);
if (me->editflag & ME_EDIT_MIRROR_X) {
if (em) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
}
else {
int v_act = BKE_mesh_mselect_active_get(me, ME_VSEL);
ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
}
}
}
static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
MDeformVert *dvert_act;
int i, vgroup_tot, subset_count;
const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
if (em) {
BMIter iter;
BMVert *eve, *eve_act;
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
if (dvert_act == NULL) {
return;
}
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
}
else {
MDeformVert *dv;
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act == NULL) {
return;
}
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && dv != dvert_act) {
defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
}
MEM_freeN((void *)vgroup_validmap);
}
/***********************Start weight transfer (WT)*********************************/
typedef enum WT_VertexGroupMode {
@ -470,8 +703,8 @@ static EnumPropertyItem WT_vertex_group_select_item[] = {
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem *rna_vertex_group_selection_itemf_helper(
bContext *C, PointerRNA *UNUSED(ptr),
EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
const bContext *C, PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), int *free, const unsigned int selection_mask)
{
Object *ob;
@ -505,13 +738,13 @@ static EnumPropertyItem *rna_vertex_group_selection_itemf_helper(
static EnumPropertyItem *rna_vertex_group_with_single_itemf(bContext *C, PointerRNA *ptr,
PropertyRNA *prop, int *free)
{
return rna_vertex_group_selection_itemf_helper(C, ptr, prop, free, WT_VGROUP_MASK_ALL);
return ED_object_vgroup_selection_itemf_helper(C, ptr, prop, free, WT_VGROUP_MASK_ALL);
}
static EnumPropertyItem *rna_vertex_group_select_itemf(bContext *C, PointerRNA *ptr,
PropertyRNA *prop, int *free)
{
return rna_vertex_group_selection_itemf_helper(C, ptr, prop, free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE));
return ED_object_vgroup_selection_itemf_helper(C, ptr, prop, free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE));
}
static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_active)
@ -1172,11 +1405,6 @@ bool *ED_vgroup_subset_from_select_type(Object *ob, eVGroupSelect subset_type, i
*r_vgroup_tot = BLI_countlist(&ob->defbase);
switch (subset_type) {
case WT_VGROUP_ALL:
vgroup_validmap = MEM_mallocN(*r_vgroup_tot * sizeof(*vgroup_validmap), __func__);
memset(vgroup_validmap, true, *r_vgroup_tot * sizeof(*vgroup_validmap));
*r_subset_count = *r_vgroup_tot;
break;
case WT_VGROUP_ACTIVE:
{
const int def_nr_active = ob->actdef - 1;
@ -1191,18 +1419,42 @@ bool *ED_vgroup_subset_from_select_type(Object *ob, eVGroupSelect subset_type, i
}
break;
}
case WT_VGROUP_BONE_SELECT: {
case WT_VGROUP_BONE_SELECT:
{
vgroup_validmap = BKE_objdef_selected_get(ob, *r_vgroup_tot, r_subset_count);
break;
}
case WT_VGROUP_BONE_DEFORM: {
case WT_VGROUP_BONE_DEFORM:
{
int i;
vgroup_validmap = BKE_objdef_validmap_get(ob, *r_vgroup_tot);
*r_subset_count = 0;
for (i = 0; i < *r_vgroup_tot; i++) {
if (vgroup_validmap[i])
if (vgroup_validmap[i] == true) {
*r_subset_count += 1;
}
}
break;
}
case WT_VGROUP_BONE_DEFORM_OFF:
{
int i;
vgroup_validmap = BKE_objdef_validmap_get(ob, *r_vgroup_tot);
*r_subset_count = 0;
for (i = 0; i < *r_vgroup_tot; i++) {
vgroup_validmap[i] = !vgroup_validmap[i];
if (vgroup_validmap[i] == true) {
*r_subset_count += 1;
}
}
break;
}
case WT_VGROUP_ALL:
default:
{
vgroup_validmap = MEM_mallocN(*r_vgroup_tot * sizeof(*vgroup_validmap), __func__);
memset(vgroup_validmap, true, *r_vgroup_tot * sizeof(*vgroup_validmap));
*r_subset_count = *r_vgroup_tot;
break;
}
}
@ -1616,7 +1868,8 @@ static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength,
}
}
static void vgroup_levels_subset(Object *ob, bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count),
static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot,
const int UNUSED(subset_count),
const float offset, const float gain)
{
MDeformWeight *dw;
@ -1746,7 +1999,9 @@ static void vgroup_lock_all(Object *ob, int action)
}
}
static void vgroup_invert_subset(Object *ob, bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), const bool auto_assign, const bool auto_remove)
static void vgroup_invert_subset(Object *ob,
const bool *vgroup_validmap, const int vgroup_tot,
const int UNUSED(subset_count), const bool auto_assign, const bool auto_remove)
{
MDeformWeight *dw;
MDeformVert *dv, **dvert_array = NULL;
@ -3001,10 +3256,9 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain);
MEM_freeN(vgroup_validmap);
MEM_freeN((void *)vgroup_validmap);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@ -3183,10 +3437,9 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove);
MEM_freeN(vgroup_validmap);
MEM_freeN((void *)vgroup_validmap);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@ -3291,10 +3544,9 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single);
MEM_freeN(vgroup_validmap);
MEM_freeN((void *)vgroup_validmap);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@ -3332,10 +3584,9 @@ static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
int remove_tot = vgroup_limit_total_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit);
MEM_freeN(vgroup_validmap);
MEM_freeN((void *)vgroup_validmap);
BKE_reportf(op->reports, remove_tot ? RPT_INFO : RPT_WARNING, "%d vertex weights limited", remove_tot);
@ -3832,3 +4083,226 @@ void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
}
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
{
MDeformVert *dvert_act;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
float weight_act;
int i;
if (em) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
BMIter iter;
BMVert *eve, *eve_act;
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
if (dvert_act == NULL) {
return;
}
weight_act = defvert_find_weight(dvert_act, def_nr);
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
MDeformWeight *dw = defvert_find_index(dv, def_nr);
if (dw) {
dw->weight = weight_act;
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
}
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
}
}
else {
MDeformVert *dv;
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act == NULL) {
return;
}
weight_act = defvert_find_weight(dvert_act, def_nr);
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
MDeformWeight *dw = defvert_find_index(dv, def_nr);
if (dw) {
dw->weight = weight_act;
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
}
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
}
}
}
static int vertex_weight_paste(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
const int wg_index = RNA_int_get(op->ptr, "weight_group");
vgroup_copy_active_to_sel_single(ob, wg_index);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot)
{
PropertyRNA *prop;
ot->name = "Paste weight to Selected";
ot->idname = "OBJECT_OT_vertex_weight_paste";
ot->description = "Copy this group's weight to other selected verts";
prop = RNA_def_int(ot->srna, "weight_group",
-1, 0, 0, "Weight Index", "Index of source weight in active Weight Group", 0, 0);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
/* api callbacks */
ot->poll = vertex_group_poll;
ot->exec = vertex_weight_paste;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int vertex_weight_delete(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
const int wg_index = RNA_int_get(op->ptr, "weight_group");
vgroup_remove_weight(ob, wg_index);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot)
{
PropertyRNA *prop;
ot->name = "Delete Weight";
ot->idname = "OBJECT_OT_vertex_weight_delete";
ot->description = "Delete this weight from the vertex";
prop = RNA_def_int(ot->srna, "weight_group",
-1, 0, 0, "Weight Index", "Index of source weight in active Weight Group", 0, 0);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
/* api callbacks */
ot->poll = vertex_group_poll;
ot->exec = vertex_weight_delete;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int vertex_weight_set_active(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
const int wg_index = RNA_int_get(op->ptr, "weight_group");
if (wg_index != -1) {
ob->actdef = wg_index + 1;
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
return OPERATOR_FINISHED;
}
void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot)
{
PropertyRNA *prop;
ot->name = "Set Active Group";
ot->idname = "OBJECT_OT_vertex_weight_set_active";
ot->description = "Set as active Vertex Group";
prop = RNA_def_int(ot->srna, "weight_group",
-1, 0, 0, "Weight Index", "Index of source weight in active Weight Group", 0, 0);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
/* api callbacks */
ot->poll = vertex_group_poll;
ot->exec = vertex_weight_set_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int vertex_weight_normalize_active(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
ToolSettings *ts = CTX_data_tool_settings(C);
eVGroupSelect subset_type = ts->vgroupsubset;
vgroup_normalize_active(ob, subset_type);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void OBJECT_OT_vertex_weight_normalize_active(wmOperatorType *ot)
{
ot->name = "Normalize Active";
ot->idname = "OBJECT_OT_vertex_weight_normalize_active";
ot->description = "Normalize Active Vert Weights";
/* api callbacks */
ot->poll = vertex_group_poll;
ot->exec = vertex_weight_normalize_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int vertex_weight_copy(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
ToolSettings *ts = CTX_data_tool_settings(C);
eVGroupSelect subset_type = ts->vgroupsubset;
vgroup_copy_active_to_sel(ob, subset_type);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void OBJECT_OT_vertex_weight_copy(wmOperatorType *ot)
{
ot->name = "Copy Active";
ot->idname = "OBJECT_OT_vertex_weight_copy";
ot->description = "Copy weights from Active to selected";
/* api callbacks */
ot->poll = vertex_group_poll;
ot->exec = vertex_weight_copy;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}

@ -830,280 +830,19 @@ static MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
}
}
/* TODO, cache flip data to speedup calls within a loop. */
static void mesh_defvert_mirror_update_internal(Object *ob,
MDeformVert *dvert_dst, MDeformVert *dvert_src,
const int def_nr)
{
if (def_nr == -1) {
/* all vgroups, add groups where neded */
int flip_map_len;
int *flip_map = defgroup_flip_map(ob, &flip_map_len, true);
defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true);
MEM_freeN(flip_map);
}
else {
/* single vgroup */
MDeformWeight *dw = defvert_verify_index(dvert_dst, defgroup_flip_index(ob, def_nr, 1));
if (dw) {
dw->weight = defvert_find_weight(dvert_src, def_nr);
}
}
}
static void ED_mesh_defvert_mirror_update_em(Object *ob, BMVert *eve, int def_nr, int vidx,
const int cd_dvert_offset)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
BMVert *eve_mirr;
eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx);
if (eve_mirr && eve_mirr != eve) {
MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
}
}
static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
{
int vidx_mirr;
Mesh *me = ob->data;
if (vidx == -1)
return;
vidx_mirr = mesh_get_x_mirror_vert(ob, vidx);
if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
MDeformVert *dvert_src = &me->dvert[vidx];
MDeformVert *dvert_dst = &me->dvert[vidx_mirr];
mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
}
}
static void vgroup_adjust_active(Object *ob, int def_nr)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
MDeformVert *dvert_act;
if (me->editflag & ME_EDIT_MIRROR_X) {
if (em) {
BMVert *eve_act;
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
if (dvert_act) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
ED_mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset);
}
}
else {
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act) {
ED_mesh_defvert_mirror_update_ob(ob, def_nr, v_act);
}
}
}
}
static void vgroup_remove_weight(Object *ob, const int def_nr)
{
MDeformVert *dvert_act;
MDeformWeight *dw;
dvert_act = ED_mesh_active_dvert_get_only(ob);
dw = defvert_find_index(dvert_act, def_nr);
defvert_remove_group(dvert_act, dw);
}
static void vgroup_copy_active_to_sel(Object *ob)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
MDeformVert *dvert_act;
int i;
if (em) {
BMIter iter;
BMVert *eve, *eve_act;
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
if (dvert_act == NULL) {
return;
}
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
defvert_copy(dv, dvert_act);
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
}
else {
MDeformVert *dv;
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act == NULL) {
return;
}
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && dv != dvert_act) {
defvert_copy(dv, dvert_act);
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
}
}
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
{
MDeformVert *dvert_act;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
float weight_act;
int i;
if (em) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
BMIter iter;
BMVert *eve, *eve_act;
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
if (dvert_act == NULL) {
return;
}
weight_act = defvert_find_weight(dvert_act, def_nr);
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
MDeformWeight *dw = defvert_find_index(dv, def_nr);
if (dw) {
dw->weight = weight_act;
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
}
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
}
}
else {
MDeformVert *dv;
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act == NULL) {
return;
}
weight_act = defvert_find_weight(dvert_act, def_nr);
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
MDeformWeight *dw = defvert_find_index(dv, def_nr);
if (dw) {
dw->weight = weight_act;
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
}
if (me->editflag & ME_EDIT_MIRROR_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
}
}
}
static void vgroup_normalize_active(Object *ob)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
BMVert *eve_act;
int v_act;
MDeformVert *dvert_act;
if (em) {
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
}
else {
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
}
if (dvert_act == NULL) {
return;
}
defvert_normalize(dvert_act);
if (me->editflag & ME_EDIT_MIRROR_X) {
if (em) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
}
else {
int v_act = BKE_mesh_mselect_active_get(me, ME_VSEL);
ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
}
}
}
static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
{
Scene *scene = CTX_data_scene(C);
Object *ob = scene->basact->object;
/* XXX TODO Use operators? */
if (event == B_VGRP_PNL_NORMALIZE) {
vgroup_normalize_active(ob);
}
else if (event == B_VGRP_PNL_COPY) {
vgroup_copy_active_to_sel(ob);
}
else if (event >= B_VGRP_PNL_ACTIVE) {
ob->actdef = event - B_VGRP_PNL_ACTIVE + 1;
}
else if (event >= B_VGRP_PNL_COPY_SINGLE) {
vgroup_copy_active_to_sel_single(ob, event - B_VGRP_PNL_COPY_SINGLE);
}
else if (event >= B_VGRP_PNL_DELETE_SINGLE) {
vgroup_remove_weight(ob, event - B_VGRP_PNL_DELETE_SINGLE);
}
else if (event >= B_VGRP_PNL_EDIT_SINGLE) {
vgroup_adjust_active(ob, event - B_VGRP_PNL_EDIT_SINGLE);
if (event < B_VGRP_PNL_EDIT_SINGLE) {
/* not for me */
return;
}
else {
BLI_assert(0);
}
#if 0 /* TODO */
if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X)
ED_vgroup_mirror(ob, 1, 1, 0);
#endif
/* default for now */
Scene *scene = CTX_data_scene(C);
Object *ob = scene->basact->object;
ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
}
static int view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
@ -1132,22 +871,39 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
dv = ED_mesh_active_dvert_get_only(ob);
if (dv && dv->totweight) {
uiLayout *col;
ToolSettings *ts = scene->toolsettings;
wmOperatorType *ot_weight_set_active = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
wmOperatorType *ot_weight_paste = WM_operatortype_find("OBJECT_OT_vertex_weight_paste", true);
wmOperatorType *ot_weight_delete = WM_operatortype_find("OBJECT_OT_vertex_weight_delete", true);
wmOperatorType *ot;
PointerRNA op_ptr, tools_ptr;
PointerRNA *but_ptr;
uiLayout *col, *bcol;
uiLayout *row;
uiLayout *box;
uiBut *but;
bDeformGroup *dg;
unsigned int i;
int subset_count, vgroup_tot;
bool *vgroup_validmap;
eVGroupSelect subset_type = WT_VGROUP_ALL;
const bool *vgroup_validmap;
eVGroupSelect subset_type = ts->vgroupsubset;
int yco = 0;
uiBlockSetHandleFunc(block, do_view3d_vgroup_buttons, NULL);
box = uiLayoutBox(pa->layout);
bcol = uiLayoutColumn(pa->layout, true);
row = uiLayoutRow(bcol, true); /* The filter button row */
RNA_pointer_create(NULL, &RNA_ToolSettings, ts, &tools_ptr);
uiItemR(row, &tools_ptr, "vertex_group_subset", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(bcol, true);
box = uiLayoutBox(col); /* The list box */
col = uiLayoutColumn(box, true);
vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) {
if (vgroup_validmap[i]) {
@ -1155,56 +911,68 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
if (dw) {
int x, xco = 0;
row = uiLayoutRow(col, true);
(void)row;
uiBlockSetEmboss(block, UI_EMBOSSN);
but = uiDefBut(block, BUT, B_VGRP_PNL_ACTIVE + i, dg->name,
xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y,
NULL, 0.0, 1.0, 1, 3, "");
uiButSetFlag(but, UI_TEXT_LEFT);
/* The Weight Group Name */
ot = ot_weight_set_active;
but = uiDefButO_ptr(block, BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
but_ptr = uiButGetOperatorPtrRNA(but);
RNA_int_set(but_ptr, "weight_group", i);
uiButSetFlag(but, UI_TEXT_LEFT);
if (ob->actdef != i + 1) {
uiButSetFlag(but, UI_BUT_INACTIVE);
}
xco += x;
//uiBlockSetEmboss(block, UI_EMBOSS);
/* The weight group value */
/* To be reworked still */
but = uiDefButF(block, NUM, B_VGRP_PNL_EDIT_SINGLE + i, "",
xco, yco, (x = UI_UNIT_X * 4), UI_UNIT_Y,
&dw->weight, 0.0, 1.0, 1, 3, "");
uiButSetFlag(but, UI_TEXT_LEFT);
xco += x;
uiDefIconBut(block, BUT, B_VGRP_PNL_COPY_SINGLE + i, ICON_PASTEDOWN,
xco, yco, (x = UI_UNIT_X), UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Copy this group's weight to other selected verts"));
xco += x;
/* The weight group paste function */
uiDefIconBut(block, BUT, B_VGRP_PNL_DELETE_SINGLE + i, ICON_X,
xco, yco, (x = UI_UNIT_X), UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Delete this weight from the vertex"));
xco += x;
ot = ot_weight_paste;
WM_operator_properties_create_ptr(&op_ptr, ot);
RNA_int_set(&op_ptr, "weight_group", i);
uiItemFullO_ptr(row, ot, "", ICON_PASTEDOWN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
/* The weight entry delete function */
ot = ot_weight_delete;
WM_operator_properties_create_ptr(&op_ptr, ot);
RNA_int_set(&op_ptr, "weight_group", i);
uiItemFullO_ptr(row, ot, "", ICON_X, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
yco -= UI_UNIT_Y;
(void)xco;
}
}
}
MEM_freeN(vgroup_validmap);
MEM_freeN((void *)vgroup_validmap);
uiBlockSetEmboss(block, UI_EMBOSS);
yco -= 2;
uiBlockSetEmboss(block, UI_EMBOSS);
col = uiLayoutColumn(pa->layout, true);
row = uiLayoutRow(col, true);
uiDefBut(block, BUT, B_VGRP_PNL_NORMALIZE, IFACE_("Normalize"),
0, yco, UI_UNIT_X * 5, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Normalize active vertex weights"));
uiDefBut(block, BUT, B_VGRP_PNL_COPY, IFACE_("Copy"),
UI_UNIT_X * 5, yco, UI_UNIT_X * 5, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Copy active vertex to other selected verts"));
ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active", 1);
but = uiDefButO_ptr(block, BUT, ot, WM_OP_EXEC_DEFAULT, "Normalize",
0, yco,UI_UNIT_X * 5, UI_UNIT_Y,
TIP_("Normalize active vertex weights"));
ot = WM_operatortype_find("OBJECT_OT_vertex_weight_copy", 1);
but = uiDefButO_ptr(block, BUT, ot, WM_OP_EXEC_DEFAULT, "Copy",
UI_UNIT_X * 5, yco,UI_UNIT_X * 5, UI_UNIT_Y,
TIP_("Copy active vertex to other selected verts"));
}
}

@ -1076,11 +1076,11 @@ typedef struct ToolSettings {
short proportional, prop_mode;
char proportional_objects; /* proportional edit, object mode */
char proportional_mask; /* proportional edit, object mode */
char pad4[1];
char auto_normalize; /*auto normalizing mode in wpaint*/
char multipaint; /* paint multiple bones in wpaint */
char weightuser;
char vgroupsubset; /* subset selection filter in wpaint */
/* UV painting */
int use_uv_sculpt;
@ -1511,6 +1511,24 @@ enum {
OB_DRAW_GROUPUSER_ALL = 2
};
/* toolsettings->vgroupsubset */
/* object_vgroup.c */
typedef enum eVGroupSelect {
WT_VGROUP_ALL = 0,
WT_VGROUP_ACTIVE = 1,
WT_VGROUP_BONE_SELECT = 2,
WT_VGROUP_BONE_DEFORM = 3,
WT_VGROUP_BONE_DEFORM_OFF = 4
} eVGroupSelect;
#define WT_VGROUP_MASK_ALL \
((1 << WT_VGROUP_ACTIVE) | \
(1 << WT_VGROUP_BONE_SELECT) | \
(1 << WT_VGROUP_BONE_DEFORM) | \
(1 << WT_VGROUP_BONE_DEFORM_OFF) | \
(1 << WT_VGROUP_ALL))
/* sce->flag */
#define SCE_DS_SELECTED (1<<0)
#define SCE_DS_COLLAPSED (1<<1)

@ -1640,6 +1640,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem vertex_group_select_items[] = {
{WT_VGROUP_ALL, "ALL", 0, "All", "All Vertex Groups"},
{WT_VGROUP_BONE_DEFORM, "BONE_DEFORM", 0, "Deform", "Vertex Groups assigned to Deform Bones"},
{WT_VGROUP_BONE_DEFORM_OFF, "OTHER_DEFORM", 0, "Other", "Vertex Groups assigned to non Deform Bones"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "ToolSettings", NULL);
RNA_def_struct_path_func(srna, "rna_ToolSettings_path");
RNA_def_struct_ui_text(srna, "Tool Settings", "");
@ -1668,10 +1676,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mask Non-Group Vertices", "Display unweighted vertices (multi-paint overrides)");
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_group_subset", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "vgroupsubset");
RNA_def_property_enum_items(prop, vertex_group_select_items);
RNA_def_property_ui_text(prop, "Subset", "Filter Vertex groups for Display");
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_paint", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "vpaint");
RNA_def_property_ui_text(prop, "Vertex Paint", "");
RNA_def_property_pointer_sdna(prop, NULL, "vpaint"); RNA_def_property_ui_text(prop, "Vertex Paint", "");
prop = RNA_def_property(srna, "weight_paint", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "wpaint");