Animation: Armature symmetrize ebones refactor #106487
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1089,6 +1096,71 @@ static EditBone *get_symmetrized_bone(bArmature *arm, EditBone *bone)
|
|||
return (mirror != NULL) ? mirror : bone;
|
||||
}
|
||||
|
||||
static void ED_armature_set_symmetrizable_ebone_selection(bArmature *arm, int axis, int direction)
|
||||
|
||||
{
|
||||
/* Deselects 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.*/
|
||||
EditBone *ebone_iter;
|
||||
|
||||
for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
|
||||
if (!(EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED))) {
|
||||
/* ignore selected bones which are invisble */
|
||||
continue;
|
||||
}
|
||||
|
||||
char name_flip[MAXBONENAME];
|
||||
|
||||
if (ebone_iter == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
|
||||
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
|
||||
|
||||
if (!ebone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ebone->flag & BONE_SELECTED) == 0) {
|
||||
/* ebone is only once selected per side */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* complicated - choose which direction to copy */
|
||||
float axis_delta;
|
||||
|
||||
axis_delta = ebone->head[axis] - ebone_iter->head[axis];
|
||||
if (axis_delta == 0.0f) {
|
||||
axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
|
||||
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// deselect depending on direction
|
||||
if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
|
||||
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
else {
|
||||
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* near duplicate of #armature_duplicate_selected_exec,
|
||||
* except for parenting part (keep in sync)
|
||||
|
@ -1109,69 +1181,26 @@ 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? */
|
||||
|
||||
Sybren A. Stüvel
commented
When you're here in the code, When you're here in the code, `ebone` is guaranteed to be non-`NULL`.
And even if it were to be `NULL`, setting `ebone_iter->temp.ebone = NULL` in that case also wouldn't hurt.
Denys Hsu
commented
Right, I've overlooked that, thanks. Right, I've overlooked that, thanks.
|
||||
preEditBoneDuplicate(arm->edbo);
|
||||
|
||||
/* Select mirrored bones */
|
||||
ED_armature_set_symmetrizable_ebone_selection(arm, axis, direction);
|
||||
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];
|
||||
|
||||
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
axis_delta = ebone->head[axis] - ebone_iter->head[axis];
|
||||
if (axis_delta == 0.0f) {
|
||||
axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ebone_src->temp.ebone = ebone_dst;
|
||||
ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
EditBone *ebone;
|
||||
/* Set temp pointer to mirrored ebones */
|
||||
ebone = ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter);
|
||||
if (ebone) {
|
||||
ebone_iter->temp.ebone = ebone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1194,11 +1223,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 */
|
||||
Sybren A. Stüvel
commented
Comments nowadays should be a full sentence, so start with a capital and end with a period. Touching is fixing ;-) Comments nowadays should be a full sentence, so start with a capital and end with a period. Touching is fixing ;-)
|
||||
if (!STREQ(name_flip, ebone_iter->name)) {
|
||||
EditBone *ebone;
|
||||
|
||||
|
@ -1241,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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
No need to have an
ED_armature
prefix, those are only for functions that are declared in the header files (and thus part of Blender's internal API).Also
axis
anddirection
can be declared asconst int
.