diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-06-12 20:20:07 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-06-12 20:24:07 +0300 |
commit | 1b8a785d83c85c2b9d605985c377191663ea13fb (patch) | |
tree | e034491af83b51862fcfa0eb294a39c6667f597d | |
parent | 07562a4afb301cf61bdaf9ed4b2b0f37150da6dd (diff) |
Armature: add armature dissolve
Works like mesh dissolve (access from delete or Ctrl+X)
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_action.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/action.c | 51 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_edit.c | 219 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_ops.c | 6 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_utils.c | 12 |
7 files changed, 260 insertions, 48 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 43859a3a6a8..830c70ea20f 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2789,6 +2789,20 @@ class VIEW3D_MT_edit_armature_roll(Menu): layout.operator("transform.transform", text="Set Roll").mode = 'BONE_ROLL' + +class VIEW3D_MT_edit_armature_delete(Menu): + bl_label = "Delete" + + def draw(self, context): + layout = self.layout + + layout.operator("armature.delete", text="Delete Bones") + + layout.separator() + + layout.operator("armature.dissolve", text="Dissolve") + + # ********** Panel ********** diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index fdb465f7105..3fceef5d95d 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -140,6 +140,10 @@ void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_us void BKE_pose_channels_hash_make(struct bPose *pose); void BKE_pose_channels_hash_free(struct bPose *pose); +void BKE_pose_channels_remove( + struct Object *ob, + bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data); + void BKE_pose_free(struct bPose *pose); void BKE_pose_free_ex(struct bPose *pose, bool do_id_user); void BKE_pose_copy_data(struct bPose **dst, struct bPose *src, const bool copy_constraints); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 7e09ad355a7..1b73978b524 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -717,6 +717,57 @@ void BKE_pose_channels_hash_free(bPose *pose) } /** + * Selectively remove pose channels. + */ +void BKE_pose_channels_remove( + Object *ob, + bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data) +{ + /* First erase any associated pose channel */ + if (ob->pose) { + bPoseChannel *pchan, *pchan_next; + bConstraint *con; + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan_next) { + pchan_next = pchan->next; + + if (filter_fn(pchan->name, user_data)) { + BKE_pose_channel_free(pchan); + if (ob->pose->chanhash) { + BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL); + } + BLI_freelinkN(&ob->pose->chanbase, pchan); + } + else { + for (con = pchan->constraints.first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct = targets.first; ct; ct = ct->next) { + if (ct->tar == ob) { + if (ct->subtarget[0]) { + if (filter_fn(ct->subtarget, user_data)) { + con->flag |= CONSTRAINT_DISABLE; + ct->subtarget[0] = 0; + } + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + } + } +} + +/** * Deallocates a pose channel. * Does not free the pose channel itself. */ diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index d4df77753eb..b3297db6176 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -42,6 +42,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_ghash.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -1233,13 +1234,21 @@ void ARMATURE_OT_split(wmOperatorType *ot) /* ********************************* Delete ******************************* */ +static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p) +{ + bArmature *arm = arm_p; + EditBone *ebone; + + ebone = ED_armature_bone_find_name(arm->edbo, bone_name); + return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer)); +} + /* previously delete_armature */ /* only editmode! */ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) { bArmature *arm; EditBone *curBone, *ebone_next; - bConstraint *con; Object *obedit = CTX_data_edit_object(C); // XXX get from context bool changed = false; arm = obedit->data; @@ -1250,48 +1259,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) armature_select_mirrored(arm); - /* First erase any associated pose channel */ - if (obedit->pose) { - bPoseChannel *pchan, *pchan_next; - for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) { - pchan_next = pchan->next; - curBone = ED_armature_bone_find_name(arm->edbo, pchan->name); - - if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) { - BKE_pose_channel_free(pchan); - BKE_pose_channels_hash_free(obedit->pose); - BLI_freelinkN(&obedit->pose->chanbase, pchan); - } - else { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == obedit) { - if (ct->subtarget[0]) { - curBone = ED_armature_bone_find_name(arm->edbo, ct->subtarget); - if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) { - con->flag |= CONSTRAINT_DISABLE; - ct->subtarget[0] = 0; - } - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - } - } - - + BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm); + for (curBone = arm->edbo->first; curBone; curBone = ebone_next) { ebone_next = curBone->next; if (arm->layer & curBone->layer) { @@ -1329,6 +1298,170 @@ void ARMATURE_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p) +{ + bArmature *arm = arm_p; + EditBone *ebone; + + ebone = ED_armature_bone_find_name(arm->edbo, bone_name); + return (ebone && (ebone->flag & BONE_DONE)); +} + +static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bArmature *arm; + EditBone *ebone, *ebone_next; + Object *obedit = CTX_data_edit_object(C); + bool changed = false; + + /* store for mirror */ + GHash *ebone_flag_orig = NULL; + int ebone_num = 0; + + arm = obedit->data; + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + ebone->temp.p = NULL; + ebone->flag &= ~BONE_DONE; + ebone_num++; + } + + if (arm->flag & ARM_MIRROR_EDIT) { + GHashIterator gh_iter; + + ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num); + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + union { int flag; void *p; } val = {0}; + val.flag = ebone->flag; + BLI_ghash_insert(ebone_flag_orig, ebone, val.p); + } + + armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); + + GHASH_ITER (gh_iter, ebone_flag_orig) { + union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter); + ebone = BLI_ghashIterator_getKey(&gh_iter); + val_p->flag = ebone->flag & ~val_p->flag; + } + } + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->parent && ebone->flag & BONE_CONNECTED) { + if (ebone->parent->temp.ebone == ebone->parent) { + /* ignore */ + } + else if (ebone->parent->temp.ebone) { + /* set ignored */ + ebone->parent->temp.ebone = ebone->parent; + } + else { + /* set child */ + ebone->parent->temp.ebone = ebone; + } + } + } + + /* cleanup multiple used bones */ + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->temp.ebone == ebone) { + ebone->temp.ebone = NULL; + } + } + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + /* break connections for unseen bones */ + if (((arm->layer & ebone->layer) && + ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0) + { + ebone->temp.ebone = NULL; + } + + if (((arm->layer & ebone->layer) && + ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0) + { + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + ebone->parent->temp.ebone = NULL; + } + + } + } + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + + if (ebone->parent && + (ebone->parent->temp.ebone == ebone)) + { + ebone->flag |= BONE_DONE; + } + } + + BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm); + + for (ebone = arm->edbo->first; ebone; ebone = ebone_next) { + ebone_next = ebone->next; + + if (ebone->flag & BONE_DONE) { + copy_v3_v3(ebone->parent->tail, ebone->tail); + ebone->parent->rad_tail = ebone->rad_tail; + + ED_armature_edit_bone_remove(arm, ebone); + changed = true; + } + } + + if (changed) { + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->parent && + ebone->parent->temp.ebone && + (ebone->flag & BONE_CONNECTED) == 0) + { + ebone->flag |= BONE_CONNECTED; + ebone->rad_head = ebone->parent->rad_head; + } + } + + if (arm->flag & ARM_MIRROR_EDIT) { + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone); + if (val_p && val_p->flag) { + ebone->flag &= ~val_p->flag; + } + } + } + } + + if (arm->flag & ARM_MIRROR_EDIT) { + BLI_ghash_free(ebone_flag_orig, NULL, NULL); + } + + if (!changed) { + return OPERATOR_CANCELLED; + } + + ED_armature_sync_selection(arm->edbo); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void ARMATURE_OT_dissolve(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Dissolve Selected Bone(s)"; + ot->idname = "ARMATURE_OT_dissolve"; + ot->description = "Dissolve selected bones from the armature"; + + /* api callbacks */ + ot->exec = armature_dissolve_selected_exec; + ot->poll = ED_operator_editarmature; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + + /* ********************************* Show/Hide ******************************* */ static int armature_hide_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 0607bc49515..2968851f2eb 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -71,6 +71,7 @@ void ARMATURE_OT_select_similar(struct wmOperatorType *ot); void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot); void ARMATURE_OT_delete(struct wmOperatorType *ot); +void ARMATURE_OT_dissolve(struct wmOperatorType *ot); void ARMATURE_OT_duplicate(struct wmOperatorType *ot); void ARMATURE_OT_symmetrize(struct wmOperatorType *ot); void ARMATURE_OT_extrude(struct wmOperatorType *ot); @@ -234,6 +235,7 @@ EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]); void bone_free(struct bArmature *arm, struct EditBone *bone); void armature_tag_select_mirrored(struct bArmature *arm); +void armature_select_mirrored_ex(struct bArmature *arm, const int flag); void armature_select_mirrored(struct bArmature *arm); void armature_tag_unselect(struct bArmature *arm); diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index ea435e3e4fa..e7f036f6911 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -65,6 +65,7 @@ void ED_operatortypes_armature(void) WM_operatortype_append(ARMATURE_OT_shortest_path_pick); WM_operatortype_append(ARMATURE_OT_delete); + WM_operatortype_append(ARMATURE_OT_dissolve); WM_operatortype_append(ARMATURE_OT_duplicate); WM_operatortype_append(ARMATURE_OT_symmetrize); WM_operatortype_append(ARMATURE_OT_extrude); @@ -266,8 +267,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ARMATURE_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "ARMATURE_OT_delete", XKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "ARMATURE_OT_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_move", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_forked", EKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 18351950462..09284860ec4 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -276,18 +276,19 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo) /* helper function for tools to work on mirrored parts. * it leaves mirrored bones selected then too, which is a good indication of what happened */ -void armature_select_mirrored(bArmature *arm) +void armature_select_mirrored_ex(bArmature *arm, const int flag) { + BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0); /* Select mirrored bones */ if (arm->flag & ARM_MIRROR_EDIT) { EditBone *curBone, *ebone_mirr; for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { if (arm->layer & curBone->layer) { - if (curBone->flag & BONE_SELECTED) { + if (curBone->flag & flag) { ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone); if (ebone_mirr) - ebone_mirr->flag |= BONE_SELECTED; + ebone_mirr->flag |= (curBone->flag & flag); } } } @@ -295,6 +296,11 @@ void armature_select_mirrored(bArmature *arm) } +void armature_select_mirrored(bArmature *arm) +{ + armature_select_mirrored_ex(arm, BONE_SELECTED); +} + void armature_tag_select_mirrored(bArmature *arm) { EditBone *curBone; |