diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index 5e8cd8d90fa..07bdbc1009b 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -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); diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 371f64fd468..edeef26ed58 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -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) { diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 0b25c494ba9..1ee3ae1283d 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -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 */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index b2810031474..e891f648713 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -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 } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index e138d2fe24a..485987fd8fe 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -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); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 594dfd6e271..3afb04c34f6 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -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); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 80ca0b38f8c..6da403074e8 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -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,20 +1419,44 @@ 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; + } } return vgroup_validmap; @@ -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; +} diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 2fa901a2f28..54173893847 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -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); + 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); } - -#if 0 /* TODO */ - if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) - ED_vgroup_mirror(ob, 1, 1, 0); -#endif - - /* default for now */ - 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")); + } } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index e08ecf6dff8..5e877ed697b 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -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) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 0c3f4aa073b..d46b1a28439 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -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");