diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 0436ee7a442..05851d8694f 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -327,6 +327,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob) if (!ebone_dst) { ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src); } + if (ebone_dst) { BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name); } @@ -334,22 +335,28 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob) LISTBASE_FOREACH (EditBone *, ebone_src, editbones) { EditBone *ebone_dst = ebone_src->temp.ebone; - if (ebone_dst) { - bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name); - if (pchan_src) { - bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name); - if (pchan_dst) { - if (pchan_src->custom_tx) { - pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx); - } - if (pchan_src->bbone_prev) { - pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev); - } - if (pchan_src->bbone_next) { - pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next); - } - } - } + if (!ebone_dst) { + continue; + } + + bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name); + if (!pchan_src) { + continue; + } + + bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name); + if (!pchan_dst) { + continue; + } + + if (pchan_src->custom_tx) { + pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx); + } + if (pchan_src->bbone_prev) { + pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev); + } + if (pchan_src->bbone_next) { + pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next); } } @@ -1120,71 +1127,80 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( scene, view_layer, CTX_wm_view3d(C), &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - bArmature *arm = obedit->data; - EditBone *ebone_iter; /* The beginning of the duplicated mirrored bones in the edbo list */ EditBone *ebone_first_dupe = NULL; + Object *obedit = objects[ob_index]; + bArmature *arm = obedit->data; + ED_armature_edit_sync_selection(arm->edbo); /* XXX why is this needed? */ preEditBoneDuplicate(arm->edbo); - /* Select mirrored bones */ + /* Deselect ebones depending on input axis and direction. + * A symmetrizable selection contains selected ebones of the input direction + * and unique selected bones with an unique flippable name. + * + * Storing temp ptrs to mirrored unselected ebones. */ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { - if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { - char name_flip[MAXBONENAME]; + if (!(EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED))) { + /* Skipping invisible selected bones. */ + continue; + } - BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); + char name_flip[MAXBONENAME]; + if (ebone_iter == NULL) { + continue; + } - if (STREQ(name_flip, ebone_iter->name)) { - /* if the name matches, we don't have the potential to be mirrored, just skip */ - ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip); + BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); - if (ebone) { - if ((ebone->flag & BONE_SELECTED) == 0) { - /* simple case, we're selected, the other bone isn't! */ - ebone_iter->temp.ebone = ebone; - } - else { - /* complicated - choose which direction to copy */ - float axis_delta; + if (STREQ(name_flip, ebone_iter->name)) { + /* Skipping ebones without flippable as they don't have the potential to be mirrored. */ + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + continue; + } - axis_delta = ebone->head[axis] - ebone_iter->head[axis]; - if (axis_delta == 0.0f) { - axis_delta = ebone->tail[axis] - ebone_iter->tail[axis]; - } + EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip); - if (axis_delta == 0.0f) { - /* Both mirrored bones exist and point to each other and overlap exactly. - * - * in this case there's no well defined solution, so de-select both and skip. - */ - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - EditBone *ebone_src, *ebone_dst; - if (((axis_delta < 0.0f) ? -1 : 1) == direction) { - ebone_src = ebone; - ebone_dst = ebone_iter; - } - else { - ebone_src = ebone_iter; - ebone_dst = ebone; - } + if (!ebone) { + /* The ebone_iter is unique and mirrorable. */ + continue; + } - ebone_src->temp.ebone = ebone_dst; - ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - } + if (ebone->flag & BONE_SELECTED) { + /* The mirrored ebone and the ebone_iter are selected. + * Deselect based on the input direction and axis. */ + float axis_delta; + + axis_delta = ebone->head[axis] - ebone_iter->head[axis]; + if (axis_delta == 0.0f) { + /* The ebone heads are overlapping. */ + axis_delta = ebone->tail[axis] - ebone_iter->tail[axis]; + + if (axis_delta == 0.0f) { + /* Both mirrored bones point to each other and overlap exactly. + * In this case there's no well defined solution, so de-select both and skip. */ + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + continue; } } + + /* Deselect depending on direction. */ + if (((axis_delta < 0.0f) ? -1 : 1) == direction) { + /* Don't store temp ptr if the iter_bone gets deselected. + * In this case, the ebone.temp should point to the ebone_iter. */ + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + continue; + } + + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } + + /* Set temp pointer to mirrored ebones */ + ebone_iter->temp.ebone = ebone; } /* Find the selected bones and duplicate them as needed, with mirrored name. */ @@ -1206,11 +1222,12 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) ebone_iter->temp.ebone->inherit_scale_mode = ebone_iter->inherit_scale_mode; continue; } + char name_flip[MAXBONENAME]; BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); - /* bones must have a side-suffix */ + /* mirrored bones must have a side-suffix */ if (!STREQ(name_flip, ebone_iter->name)) { EditBone *ebone; @@ -1254,8 +1271,8 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) */ if (ebone->head[axis] != 0.0f) { - /* The mirrored bone doesn't start on the mirror axis, so assume that this one should - * not be connected to the old parent */ + /* The mirrored bone doesn't start on the mirror axis, so assume that this one + * should not be connected to the old parent */ ebone->flag &= ~BONE_CONNECTED; } }