static int armature_merge_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); bArmature *arm = (obedit) ? obedit->data : NULL; short type = RNA_enum_get(op->ptr, "type"); /* sanity checks */ if (ELEM(NULL, obedit, arm)) return OPERATOR_CANCELLED; /* for now, there's only really one type of merging that's performed... */ if (type == 1) { /* go down chains, merging bones */ ListBase chains = {NULL, NULL}; LinkData *chain, *nchain; EditBone *ebo; armature_tag_select_mirrored(arm); /* get chains (ends on chains) */ chains_find_tips(arm->edbo, &chains); if (chains.first == NULL) return OPERATOR_CANCELLED; /* each 'chain' is the last bone in the chain (with no children) */ for (chain = chains.first; chain; chain = nchain) { EditBone *bstart = NULL, *bend = NULL; EditBone *bchild = NULL, *child = NULL; /* temporarily remove chain from list of chains */ nchain = chain->next; BLI_remlink(&chains, chain); /* only consider bones that are visible and selected */ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) { /* check if visible + selected */ if (EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) && (ebo->flag & BONE_SELECTED) ) { /* set either end or start (end gets priority, unless it is already set) */ if (bend == NULL) { bend = ebo; bchild = child; } else bstart = ebo; } else { /* chain is broken... merge any continous segments then clear */ if (bstart && bend) bones_merge(obedit, bstart, bend, bchild, &chains); bstart = NULL; bend = NULL; bchild = NULL; } } /* merge from bstart to bend if something not merged */ if (bstart && bend) bones_merge(obedit, bstart, bend, bchild, &chains); /* put back link */ BLI_insertlinkbefore(&chains, nchain, chain); } armature_tag_unselect(arm); BLI_freelistN(&chains); } /* updates */ ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); return OPERATOR_FINISHED; }
static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_edit_object(C); bArmature *arm = (bArmature *)ob->data; ListBase chains = {NULL, NULL}; LinkData *chain; /* get chains of bones (ends on chains) */ chains_find_tips(arm->edbo, &chains); if (BLI_listbase_is_empty(&chains)) return OPERATOR_CANCELLED; /* ensure that mirror bones will also be operated on */ armature_tag_select_mirrored(arm); /* clear BONE_TRANSFORM flags * - used to prevent duplicate/canceling operations from occurring [#34123] * - BONE_DONE cannot be used here as that's already used for mirroring */ armature_clear_swap_done_flags(arm); /* loop over chains, only considering selected and visible bones */ for (chain = chains.first; chain; chain = chain->next) { EditBone *ebo, *child = NULL, *parent = NULL; /* loop over bones in chain */ for (ebo = chain->data; ebo; ebo = parent) { /* parent is this bone's original parent * - we store this, as the next bone that is checked is this one * but the value of ebo->parent may change here... */ parent = ebo->parent; /* skip bone if already handled... [#34123] */ if ((ebo->flag & BONE_TRANSFORM) == 0) { /* only if selected and editable */ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) { /* swap head and tail coordinates */ swap_v3_v3(ebo->head, ebo->tail); /* do parent swapping: * - use 'child' as new parent * - connected flag is only set if points are coincidental */ ebo->parent = child; if ((child) && equals_v3v3(ebo->head, child->tail)) ebo->flag |= BONE_CONNECTED; else ebo->flag &= ~BONE_CONNECTED; /* get next bones * - child will become the new parent of next bone */ child = ebo; } else { /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it * as it will be facing in opposite direction */ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) { ebo->parent = NULL; ebo->flag &= ~BONE_CONNECTED; } /* get next bones * - child will become new parent of next bone (not swapping occurred, * so set to NULL to prevent infinite-loop) */ child = NULL; } /* tag as done (to prevent double-swaps) */ ebo->flag |= BONE_TRANSFORM; } } } /* free chains */ BLI_freelistN(&chains); /* clear temp flags */ armature_clear_swap_done_flags(arm); armature_tag_unselect(arm); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); return OPERATOR_FINISHED; }