diff options
Diffstat (limited to 'source/blender/editors/armature')
17 files changed, 617 insertions, 343 deletions
diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h index 21e85b6fe89..aa56f847f00 100644 --- a/source/blender/editors/armature/BIF_retarget.h +++ b/source/blender/editors/armature/BIF_retarget.h @@ -40,7 +40,6 @@ struct bContext; struct EditBone; -struct RigJoint; struct RigGraph; struct RigNode; struct RigArc; diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 22aaeccc4a8..e3a69a89a57 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -43,6 +43,7 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_idprop.h" +#include "BKE_deform.h" #include "RNA_access.h" #include "RNA_define.h" @@ -89,7 +90,7 @@ EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length, bArmature *arm = obedit_arm->data; EditBone *bone; - ED_armature_deselect_all(obedit_arm, 0); + ED_armature_deselect_all(obedit_arm); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); @@ -144,7 +145,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) to_root = 1; } - ED_armature_deselect_all(obedit, 0); + ED_armature_deselect_all(obedit); /* we re-use code for mirror editing... */ flipbone = NULL; @@ -282,12 +283,8 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name) * */ void preEditBoneDuplicate(ListBase *editbones) { - EditBone *eBone; - /* clear temp */ - for (eBone = editbones->first; eBone; eBone = eBone->next) { - eBone->temp = NULL; - } + ED_armature_ebone_listbase_temp_clear(editbones); } /* @@ -311,7 +308,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj /* does this constraint have a subtarget in * this armature? */ - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -327,8 +324,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj * so, update the constraint to point at the * duplicate of the old subtarget. */ - if (oldtarget->temp) { - newtarget = (EditBone *) oldtarget->temp; + if (oldtarget->temp.ebone) { + newtarget = oldtarget->temp.ebone; BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget)); } } @@ -357,8 +354,8 @@ EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase /* Copy data from old bone to new bone */ memcpy(eBone, curBone, sizeof(EditBone)); - curBone->temp = eBone; - eBone->temp = curBone; + curBone->temp.ebone = eBone; + eBone->temp.ebone = curBone; if (name != NULL) { BLI_strncpy(eBone->name, name, sizeof(eBone->name)); @@ -398,13 +395,11 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb return duplicateEditBoneObjects(curBone, name, editbones, ob, ob); } -/* previously adduplicate_armature */ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) { bArmature *arm; - EditBone *eBone = NULL; - EditBone *curBone; - EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */ + EditBone *ebone_iter; + EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */ Object *obedit = CTX_data_edit_object(C); arm = obedit->data; @@ -419,77 +414,80 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) /* Select mirrored bones */ if (arm->flag & ARM_MIRROR_EDIT) { - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) { - if (curBone->flag & BONE_SELECTED) { - eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone); - if (eBone) - eBone->flag |= BONE_SELECTED; + for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + EditBone *ebone; + + ebone = ED_armature_bone_get_mirrored(arm->edbo, ebone_iter); + if (ebone) { + ebone->flag |= BONE_SELECTED; } } } } - /* Find the selected bones and duplicate them as needed */ - for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) { - if (curBone->flag & BONE_SELECTED) { - - eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit); - - if (!firstDup) - firstDup = eBone; + /* Find the selected bones and duplicate them as needed */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + EditBone *ebone; + ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit); + + if (!ebone_first_dupe) { + ebone_first_dupe = ebone; } } } - /* Run though the list and fix the pointers */ - for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) { - if (curBone->flag & BONE_SELECTED) { - eBone = (EditBone *) curBone->temp; - - if (!curBone->parent) { - /* If this bone has no parent, - * Set the duplicate->parent to NULL - */ - eBone->parent = NULL; - } - else if (curBone->parent->temp) { - /* If this bone has a parent that was duplicated, - * Set the duplicate->parent to the curBone->parent->temp - */ - eBone->parent = (EditBone *)curBone->parent->temp; - } - else { - /* If this bone has a parent that IS not selected, - * Set the duplicate->parent to the curBone->parent - */ - eBone->parent = (EditBone *) curBone->parent; - eBone->flag &= ~BONE_CONNECTED; - } - - /* Lets try to fix any constraint subtargets that might - * have been duplicated + /* Run though the list and fix the pointers */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + EditBone *ebone = ebone_iter->temp.ebone; + + if (!ebone_iter->parent) { + /* If this bone has no parent, + * Set the duplicate->parent to NULL + */ + ebone->parent = NULL; + } + else if (ebone_iter->parent->temp.ebone) { + /* If this bone has a parent that was duplicated, + * Set the duplicate->parent to the curBone->parent->temp + */ + ebone->parent = ebone_iter->parent->temp.ebone; + } + else { + /* If this bone has a parent that IS not selected, + * Set the duplicate->parent to the curBone->parent */ - updateDuplicateSubtarget(eBone, arm->edbo, obedit); + ebone->parent = (EditBone *) ebone_iter->parent; + ebone->flag &= ~BONE_CONNECTED; } + + /* Lets try to fix any constraint subtargets that might + * have been duplicated + */ + updateDuplicateSubtarget(ebone, arm->edbo, obedit); } } /* correct the active bone */ - if (arm->act_edbone) { - eBone = arm->act_edbone; - if (eBone->temp) - arm->act_edbone = eBone->temp; + if (arm->act_edbone && arm->act_edbone->temp.ebone) { + arm->act_edbone = arm->act_edbone->temp.ebone; } - /* Deselect the old bones and select the new ones */ - for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) - curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + /* Deselect the old bones and select the new ones */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter)) { + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } } ED_armature_validate_active(arm); @@ -515,6 +513,214 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** + * near duplicate of #armature_duplicate_selected_exec, + * except for parenting part (keep in sync) + */ +static int armature_symmetrize_exec(bContext *C, wmOperator *op) +{ + bArmature *arm; + EditBone *ebone_iter; + EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */ + + Object *obedit = CTX_data_edit_object(C); + const int direction = RNA_enum_get(op->ptr, "direction"); + const int axis = 0; + + arm = obedit->data; + + /* cancel if nothing selected */ + if (CTX_DATA_COUNT(C, selected_bones) == 0) + return OPERATOR_CANCELLED; + + ED_armature_sync_selection(arm->edbo); // XXX why is this needed? + + preEditBoneDuplicate(arm->edbo); + + /* Select mirrored bones */ + 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[MAX_VGROUP_NAME]; + + BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); + + 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_bone_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 eachother and overlap exactly. + * + * in this case theres 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); + } + } + } + } + } + } + + /* Find the selected bones and duplicate them as needed, with mirrored name */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED) && + /* will be set if the mirror bone already exists (no need to make a new one) */ + (ebone_iter->temp.ebone == NULL)) + { + char name_flip[MAX_VGROUP_NAME]; + + BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); + + /* bones must have a side-suffix */ + if (!STREQ(name_flip, ebone_iter->name)) { + EditBone *ebone; + + ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit); + + if (!ebone_first_dupe) { + ebone_first_dupe = ebone; + } + } + } + } + + /* Run though the list and fix the pointers */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (ebone_iter->temp.ebone) { + /* copy all flags except for ... */ + const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); + + EditBone *ebone = ebone_iter->temp.ebone; + + /* copy flags incase bone is pre-existing data */ + ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy); + + if (ebone_iter->parent == NULL) { + /* If this bone has no parent, + * Set the duplicate->parent to NULL + */ + ebone->parent = NULL; + ebone->flag &= ~BONE_CONNECTED; + } + else { + /* the parent may have been duplicated, if not lookup the mirror parent */ + EditBone *ebone_parent = + (ebone_iter->parent->temp.ebone ? + ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent)); + + if (ebone_parent == NULL) { + /* If the mirror lookup failed, (but the current bone has a parent) + * then we can assume the parent has no L/R but is a center bone. + * So just use the same parent for both. + */ + ebone_parent = ebone_iter->parent; + ebone->flag &= ~BONE_CONNECTED; + } + + ebone->parent = ebone_parent; + } + + /* Lets try to fix any constraint subtargets that might + * have been duplicated + */ + updateDuplicateSubtarget(ebone, arm->edbo, obedit); + } + } + + transform_armature_mirror_update(obedit); + + /* Selected bones now have their 'temp' pointer set, + * so we don't need this anymore */ + + /* Deselect the old bones and select the new ones */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter)) { + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + } + + /* New bones will be selected, but some of the bones may already exist */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + EditBone *ebone = ebone_iter->temp.ebone; + if (ebone && EBONE_SELECTABLE(arm, ebone)) { + ED_armature_ebone_select_set(ebone, true); + } + } + + /* correct the active bone */ + if (arm->act_edbone && arm->act_edbone->temp.ebone) { + arm->act_edbone = arm->act_edbone->temp.ebone; + } + + ED_armature_validate_active(arm); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +/* following conventions from #MESH_OT_symmetrize */ +void ARMATURE_OT_symmetrize(wmOperatorType *ot) +{ + /* subset of 'symmetrize_direction_items' */ + static EnumPropertyItem arm_symmetrize_direction_items[] = { + {-1, "NEGATIVE_X", 0, "-X to +X", ""}, + {+1, "POSITIVE_X", 0, "+X to -X", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Symmetrize"; + ot->idname = "ARMATURE_OT_symmetrize"; + ot->description = "Enforce symmetry, make copies of the selection or use existing"; + + /* api callbacks */ + ot->exec = armature_symmetrize_exec; + ot->poll = ED_operator_editarmature; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum( + ot->srna, "direction", arm_symmetrize_direction_items, -1, + "Direction", "Which sides to copy from and to (when both are selected)"); +} + /* ------------------------------------------ */ /* previously extrude_armature */ @@ -704,7 +910,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); - ED_armature_deselect_all(obedit, 0); + ED_armature_deselect_all(obedit); /* Create a bone */ bone = ED_armature_edit_bone_add(obedit->data, name); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 88c52989c07..d4df77753eb 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -578,6 +578,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ListBase points = {NULL, NULL}; + EditBone *newbone = NULL; int count; /* sanity checks */ @@ -610,94 +611,97 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) float curs[3]; /* Get Points - selected joint */ - ebp = (EditBonePoint *)points.first; + ebp = points.first; /* Get points - cursor (tail) */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); /* Create a bone */ - /* newbone = */ add_points_bone(obedit, ebp->vec, curs); + newbone = add_points_bone(obedit, ebp->vec, curs); } else if (count == 2) { - EditBonePoint *ebp, *ebp2; + EditBonePoint *ebp_a, *ebp_b; float head[3], tail[3]; short headtail = 0; /* check that the points don't belong to the same bone */ - ebp = (EditBonePoint *)points.first; - ebp2 = ebp->next; + ebp_a = (EditBonePoint *)points.first; + ebp_b = ebp_a->next; - if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) { - BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); - BLI_freelistN(&points); - return OPERATOR_CANCELLED; - } - if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) { + if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) || + ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL))) + { BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); BLI_freelistN(&points); return OPERATOR_CANCELLED; } /* find which one should be the 'head' */ - if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) { - /* rule: whichever one is closer to 3d-cursor */ - float curs[3]; - float vecA[3], vecB[3]; - float distA, distB; - - /* get cursor location */ - invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); - - /* get distances */ - sub_v3_v3v3(vecA, ebp->vec, curs); - sub_v3_v3v3(vecB, ebp2->vec, curs); - distA = len_v3(vecA); - distB = len_v3(vecB); - - /* compare distances - closer one therefore acts as direction for bone to go */ - headtail = (distA < distB) ? 2 : 1; + if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) { + /* use active, nice predictable */ + if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) { + headtail = 1; + } + else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) { + headtail = 2; + } + else { + /* rule: whichever one is closer to 3d-cursor */ + float curs[3]; + float dist_sq_a, dist_sq_b; + + /* get cursor location */ + invert_m4_m4(obedit->imat, obedit->obmat); + mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); + + /* get distances */ + dist_sq_a = len_squared_v3v3(ebp_a->vec, curs); + dist_sq_b = len_squared_v3v3(ebp_b->vec, curs); + + /* compare distances - closer one therefore acts as direction for bone to go */ + headtail = (dist_sq_a < dist_sq_b) ? 2 : 1; + } } - else if (ebp->head_owner) { + else if (ebp_a->head_owner) { headtail = 1; } - else if (ebp2->head_owner) { + else if (ebp_b->head_owner) { headtail = 2; } /* assign head/tail combinations */ if (headtail == 2) { - copy_v3_v3(head, ebp->vec); - copy_v3_v3(tail, ebp2->vec); + copy_v3_v3(head, ebp_a->vec); + copy_v3_v3(tail, ebp_b->vec); } else if (headtail == 1) { - copy_v3_v3(head, ebp2->vec); - copy_v3_v3(tail, ebp->vec); + copy_v3_v3(head, ebp_b->vec); + copy_v3_v3(tail, ebp_a->vec); } /* add new bone and parent it to the appropriate end */ if (headtail) { - EditBone *newbone = add_points_bone(obedit, head, tail); + newbone = add_points_bone(obedit, head, tail); /* do parenting (will need to set connected flag too) */ if (headtail == 2) { /* ebp tail or head - tail gets priority */ - if (ebp->tail_owner) - newbone->parent = ebp->tail_owner; + if (ebp_a->tail_owner) + newbone->parent = ebp_a->tail_owner; else - newbone->parent = ebp->head_owner; + newbone->parent = ebp_a->head_owner; } else { - /* ebp2 tail or head - tail gets priority */ - if (ebp2->tail_owner) - newbone->parent = ebp2->tail_owner; + /* ebp_b tail or head - tail gets priority */ + if (ebp_b->tail_owner) + newbone->parent = ebp_b->tail_owner; else - newbone->parent = ebp2->head_owner; + newbone->parent = ebp_b->head_owner; } /* don't set for bone connecting two head points of bones */ - if (ebp->tail_owner || ebp2->tail_owner) { + if (ebp_a->tail_owner || ebp_b->tail_owner) { newbone->flag |= BONE_CONNECTED; } } @@ -708,6 +712,12 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) BLI_freelistN(&points); return OPERATOR_CANCELLED; } + + if (newbone) { + ED_armature_deselect_all(obedit); + arm->act_edbone = newbone; + newbone->flag |= BONE_TIPSEL; + } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); @@ -1254,7 +1264,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) } else { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 2c64c9aa345..0607bc49515 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -72,6 +72,7 @@ void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot); void ARMATURE_OT_delete(struct wmOperatorType *ot); void ARMATURE_OT_duplicate(struct wmOperatorType *ot); +void ARMATURE_OT_symmetrize(struct wmOperatorType *ot); void ARMATURE_OT_extrude(struct wmOperatorType *ot); void ARMATURE_OT_hide(struct wmOperatorType *ot); void ARMATURE_OT_reveal(struct wmOperatorType *ot); diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index a8b5f888597..eedff896315 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -104,7 +104,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char * bConstraintTarget *ct; for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; /* constraint targets */ @@ -270,7 +270,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead... { - BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname); + BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname); } /* correct view locking */ diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index c80953d6737..ea435e3e4fa 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -66,6 +66,7 @@ void ED_operatortypes_armature(void) WM_operatortype_append(ARMATURE_OT_delete); WM_operatortype_append(ARMATURE_OT_duplicate); + WM_operatortype_append(ARMATURE_OT_symmetrize); WM_operatortype_append(ARMATURE_OT_extrude); WM_operatortype_append(ARMATURE_OT_hide); WM_operatortype_append(ARMATURE_OT_reveal); @@ -275,7 +276,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ARMATURE_OT_merge", MKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_split", YKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, 0, 0); /* set flags */ WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0); @@ -411,5 +412,6 @@ void ED_keymap_armature(wmKeyConfig *keyconf) /* menus */ WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_propagate", PKEY, KM_PRESS, KM_ALT, 0); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 53989dd783c..8cda6f6db77 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -78,7 +78,7 @@ static void joined_armature_fix_links_constraints( bConstraint *con; for (con = lb->first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -380,7 +380,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (base->object->adt) { if (ob->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - ob->adt = BKE_copy_animdata(base->object->adt, false); + ob->adt = BKE_animdata_copy(base->object->adt, false); } else { /* merge in data - we'll fix the drivers manually */ @@ -391,7 +391,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (curarm->adt) { if (arm->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - arm->adt = BKE_copy_animdata(curarm->adt, false); + arm->adt = BKE_animdata_copy(curarm->adt, false); } else { /* merge in data - we'll fix the drivers manually */ @@ -435,7 +435,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -473,7 +473,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) /* fix object-level constraints */ if (ob != origArm) { for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -548,7 +548,7 @@ static void separate_armature_bones(Object *ob, short sel) for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (ebo->parent == curbone) { ebo->parent = NULL; - ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ + ebo->temp.p = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ ebo->flag &= ~BONE_CONNECTED; } } @@ -641,6 +641,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op) ED_armature_to_edit(obedit->data); + /* parents tips remain selected when connected children are removed. */ + ED_armature_deselect_all(obedit); + BKE_report(op->reports, RPT_INFO, "Separated bones"); /* note, notifier might evolve */ @@ -660,6 +663,7 @@ void ARMATURE_OT_separate(wmOperatorType *ot) ot->description = "Isolate selected bones into a separate armature"; /* callbacks */ + ot->invoke = WM_operator_confirm; ot->exec = separate_armature_exec; ot->poll = ED_operator_editarmature; diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 581dd00e285..5aa2c628252 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -54,9 +54,9 @@ #include "armature_intern.h" -/* utility macros fro storing a temp int in the bone (selection flag) */ -#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (GET_INT_FROM_POINTER((ebone)->temp))) -#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp = SET_INT_IN_POINTER(val)) +/* utility macros for storing a temp int in the bone (selection flag) */ +#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i) +#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val) /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */ @@ -388,61 +388,14 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], return NULL; } - - -/* toggle==0: deselect - * toggle==1: swap (based on test) - * toggle==2: swap (no test), CURRENTLY UNUSED - */ -void ED_armature_deselect_all(Object *obedit, int toggle) +void ED_armature_deselect_all(Object *obedit) { bArmature *arm = obedit->data; - EditBone *eBone; - int sel = 1; - - if (toggle == 1) { - /* Determine if there are any selected bones - * and therefore whether we are selecting or deselecting */ - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - // if (arm->layer & eBone->layer) { - if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { - sel = 0; - break; - } - // } - } - } - else { - sel = toggle; - } + EditBone *ebone; - /* Set the flags */ - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - if (sel == 2) { - /* invert selection of bone */ - if (EBONE_VISIBLE(arm, eBone)) { - eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (arm->act_edbone == eBone) - arm->act_edbone = NULL; - } - } - else if (sel == 1) { - /* select bone */ - if (EBONE_VISIBLE(arm, eBone)) { - eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (eBone->parent) - eBone->parent->flag |= (BONE_TIPSEL); - } - } - else { - /* deselect bone */ - eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (arm->act_edbone == eBone) - arm->act_edbone = NULL; - } + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } - - ED_armature_sync_selection(arm->edbo); } void ED_armature_deselect_all_visible(Object *obedit) @@ -489,8 +442,9 @@ bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect, nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask); if (nearBone) { - if (!extend && !deselect && !toggle) - ED_armature_deselect_all(obedit, 0); + if (!extend && !deselect && !toggle) { + ED_armature_deselect_all(obedit); + } /* by definition the non-root connected bones have no root point drawn, * so a root selection needs to be delivered to the parent tip */ @@ -731,7 +685,7 @@ static void armature_select_more_less(Object *ob, bool more) } } } - ebone->temp = NULL; + ebone->temp.p = NULL; } ED_armature_sync_selection(arm->edbo); @@ -962,75 +916,78 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot) /* ********************* select hierarchy operator ************** */ -/* Get the first available child of an editbone */ -static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility) -{ - EditBone *curbone, *chbone = NULL; - - for (curbone = arm->edbo->first; curbone; curbone = curbone->next) { - if (curbone->parent == pabone) { - if (use_visibility) { - if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) { - chbone = curbone; - } - } - else - chbone = curbone; - } - } - - return chbone; -} - static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); Object *ob; bArmature *arm; - EditBone *curbone, *pabone, *chbone; + EditBone *ebone_active; int direction = RNA_enum_get(op->ptr, "direction"); const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); + bool changed = false; ob = obedit; arm = (bArmature *)ob->data; - - for (curbone = arm->edbo->first; curbone; curbone = curbone->next) { - /* only work on bone if it is visible and its selection can change */ - if (EBONE_SELECTABLE(arm, curbone)) { - if (curbone == arm->act_edbone) { - if (direction == BONE_SELECT_PARENT) { - if (curbone->parent == NULL) continue; - else pabone = curbone->parent; - - if (EBONE_VISIBLE(arm, pabone)) { - pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_edbone = pabone; - if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL; - - if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - } - + + ebone_active = arm->act_edbone; + if (ebone_active == NULL) { + return OPERATOR_CANCELLED; + } + + if (direction == BONE_SELECT_PARENT) { + if (ebone_active->parent) { + EditBone *ebone_parent; + + ebone_parent = ebone_active->parent; + + if (EBONE_SELECTABLE(arm, ebone_parent)) { + arm->act_edbone = ebone_parent; + + if (!add_to_sel) { + ED_armature_ebone_select_set(ebone_active, false); } - else { // BONE_SELECT_CHILD - chbone = editbone_get_child(arm, curbone, 1); - if (chbone == NULL) continue; - - if (EBONE_SELECTABLE(arm, chbone)) { - chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_edbone = chbone; - - if (!add_to_sel) { - curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL); - if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL; + ED_armature_ebone_select_set(ebone_parent, true); + + changed = true; + } + } + + } + else { /* BONE_SELECT_CHILD */ + EditBone *ebone_iter, *ebone_child = NULL; + int pass; + + /* first pass, only connected bones (the logical direct child) */ + for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) { + for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + /* possible we have multiple children, some invisible */ + if (EBONE_SELECTABLE(arm, ebone_iter)) { + if (ebone_iter->parent == ebone_active) { + if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) { + ebone_child = ebone_iter; + break; } - break; } } } } + + if (ebone_child) { + arm->act_edbone = ebone_child; + + if (!add_to_sel) { + ED_armature_ebone_select_set(ebone_active, false); + } + ED_armature_ebone_select_set(ebone_child, true); + + changed = true; + } } + if (changed == false) { + return OPERATOR_CANCELLED; + } + ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 97f69d86aee..eebdd706ab2 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -488,7 +488,7 @@ static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist) /* Find the associated editbone */ for (ebone = editbonelist->first; ebone; ebone = ebone->next) - if ((Bone *)ebone->temp == curBone) + if (ebone->temp.bone == curBone) break; if (ebone) { @@ -548,7 +548,7 @@ void ED_armature_from_edit(bArmature *arm) /* Copy the bones from the editData into the armature */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = MEM_callocN(sizeof(Bone), "bone"); - eBone->temp = newBone; /* Associate the real Bones with the EditBones */ + eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name)); copy_v3_v3(newBone->arm_head, eBone->head); @@ -584,9 +584,9 @@ void ED_armature_from_edit(bArmature *arm) /* Fix parenting in a separate pass to ensure ebone->bone connections * are valid at this point */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - newBone = (Bone *)eBone->temp; + newBone = eBone->temp.bone; if (eBone->parent) { - newBone->parent = (Bone *)eBone->parent->temp; + newBone->parent = eBone->parent->temp.bone; BLI_addtail(&newBone->parent->childbase, newBone); { @@ -695,24 +695,24 @@ static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src) if (ebone_dst->prop) { ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop); } - ebone_src->temp = ebone_dst; + ebone_src->temp.ebone = ebone_dst; BLI_addtail(lb_dst, ebone_dst); } /* set pointers */ for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) { if (ebone_dst->parent) { - ebone_dst->parent = ebone_dst->parent->temp; + ebone_dst->parent = ebone_dst->parent->temp.ebone; } } } -static void ED_armature_ebone_listbase_temp_clear(ListBase *lb) +void ED_armature_ebone_listbase_temp_clear(ListBase *lb) { EditBone *ebone; /* be sure they don't hang ever */ for (ebone = lb->first; ebone; ebone = ebone->next) { - ebone->temp = NULL; + ebone->temp.p = NULL; } } @@ -733,7 +733,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) /* active bone */ if (uarm->act_edbone) { ebone = uarm->act_edbone; - arm->act_edbone = ebone->temp; + arm->act_edbone = ebone->temp.ebone; } else { arm->act_edbone = NULL; @@ -755,7 +755,7 @@ static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata)) /* active bone */ if (arm->act_edbone) { ebone = arm->act_edbone; - uarm->act_edbone = ebone->temp; + uarm->act_edbone = ebone->temp.ebone; } ED_armature_ebone_listbase_temp_clear(&uarm->lb); @@ -785,7 +785,7 @@ static void *get_armature_edit(bContext *C) void undo_push_armature(bContext *C, const char *name) { // XXX solve getdata() - undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL); + undo_editmode_push(C, name, CTX_data_edit_object, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL); } /* *************************************************************** */ diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 5376fc8c79b..2235f9f92cc 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -707,7 +707,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -832,7 +832,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index b7d14e089cf..c630ea6478a 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -127,12 +127,12 @@ struct LaplacianSystem { static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2) { - void **p = BLI_edgehash_lookup_p(edgehash, v1, v2); + void **p; - if (p) + if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p)) *p = (void *)((intptr_t)*p + (intptr_t)1); else - BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1); + *p = (void *)((intptr_t)1); } static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2) @@ -1719,7 +1719,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind /* sanity check */ for (b = 0; b < mdb->size3; b++) if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) - if (fabs(mdb->totalphi[b] - 1.0f) > 1e-4) + if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f) printf("totalphi deficiency [%s|%d] %d: %.10f\n", (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]); #endif diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h index 820aedc5467..1412136c1a8 100644 --- a/source/blender/editors/armature/meshlaplacian.h +++ b/source/blender/editors/armature/meshlaplacian.h @@ -29,11 +29,9 @@ //#define RIGID_DEFORM -struct Scene; struct Object; struct Mesh; struct bDeformGroup; -struct MeshDeformModifierData; #ifdef RIGID_DEFORM struct EditMesh; diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 549a3854bac..e87c324d7ec 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -436,7 +436,7 @@ static void pose_copy_menu(Scene *scene) pchan->constflag |= pchanact->constflag; if (ob->pose) - ob->pose->flag |= POSE_RECALC; + BKE_pose_tag_recalc(bmain, ob->pose); } break; case 6: /* Transform Locks */ @@ -550,7 +550,7 @@ static void pose_copy_menu(Scene *scene) BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */ if (ob->pose) - ob->pose->flag |= POSE_RECALC; + BKE_pose_tag_recalc(bmain, ob->pose); } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations @@ -862,7 +862,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *e /* loop over the bits for this pchan's layers, adding layers where they're needed */ for (bit = 0; bit < 32; bit++) { - layers[bit] = (pchan->bone->layer & (1 << bit)) != 0; + layers[bit] = (pchan->bone->layer & (1u << bit)) != 0; } } CTX_DATA_END; @@ -936,8 +936,9 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven /* loop over the bits for this pchan's layers, adding layers where they're needed */ for (bit = 0; bit < 32; bit++) { - if (ebone->layer & (1 << bit)) + if (ebone->layer & (1u << bit)) { layers[bit] = 1; + } } } CTX_DATA_END; diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 413a74d24b5..4d9df06f33f 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -130,6 +130,7 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U { Object *ob = ED_pose_object_from_context(C); bPose *pose; + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type"); uiPopupMenu *pup; uiLayout *layout; @@ -140,6 +141,17 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; pose = ob->pose; + + /* If group index is set, try to use it! */ + if (RNA_property_is_set(op->ptr, prop)) { + const int num_groups = BLI_listbase_count(&pose->agroups); + const int group = RNA_property_int_get(op->ptr, prop); + + /* just use the active group index, and call the exec callback for the calling operator */ + if (group > 0 && group <= num_groups) { + return op->type->exec(C, op); + } + } /* if there's no active group (or active is invalid), create a new menu to find it */ if (pose->active_group <= 0) { diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 5d5a9bf363c..3bac50ef3ed 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -62,7 +62,7 @@ #include "armature_intern.h" -/* utility macros fro storing a temp int in the bone (selection flag) */ +/* utility macros for storing a temp int in the bone (selection flag) */ #define PBONE_PREV_FLAG_GET(pchan) ((void)0, (GET_INT_FROM_POINTER((pchan)->temp))) #define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = SET_INT_IN_POINTER(val)) @@ -458,7 +458,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op { if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -518,71 +518,67 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm = ob->data; - Bone *curbone, *pabone, *chbone; + bPoseChannel *pchan_act; int direction = RNA_enum_get(op->ptr, "direction"); const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); - bool found = false; + bool changed = false; - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) - { - curbone = pchan->bone; - - if ((curbone->flag & BONE_UNSELECTABLE) == 0) { - if (curbone == arm->act_bone) { - if (direction == BONE_SELECT_PARENT) { - if (pchan->parent == NULL) continue; - else pabone = pchan->parent->bone; - - if (PBONE_SELECTABLE(arm, pabone)) { - if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; - pabone->flag |= BONE_SELECTED; - arm->act_bone = pabone; - - found = 1; - break; - } + pchan_act = BKE_pose_channel_active(ob); + if (pchan_act == NULL) { + return OPERATOR_CANCELLED; + } + + if (direction == BONE_SELECT_PARENT) { + if (pchan_act->parent) { + Bone *bone_parent; + bone_parent = pchan_act->parent->bone; + + if (PBONE_SELECTABLE(arm, bone_parent)) { + if (!add_to_sel) { + pchan_act->bone->flag &= ~BONE_SELECTED; } - else { /* direction == BONE_SELECT_CHILD */ - /* the child member is only assigned to connected bones, see [#30340] */ -#if 0 - if (pchan->child == NULL) continue; - else chbone = pchan->child->bone; -#else - /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */ - chbone = pchan->child ? pchan->child->bone : NULL; - if (chbone == NULL) { - bPoseChannel *pchan_child; - - for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) { - /* possible we have multiple children, some invisible */ - if (PBONE_SELECTABLE(arm, pchan_child->bone)) { - if (pchan_child->parent == pchan) { - chbone = pchan_child->bone; - break; - } - } - } - } + bone_parent->flag |= BONE_SELECTED; + arm->act_bone = bone_parent; - if (chbone == NULL) continue; -#endif - - if (PBONE_SELECTABLE(arm, chbone)) { - if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; - chbone->flag |= BONE_SELECTED; - arm->act_bone = chbone; - - found = 1; - break; + changed = true; + } + } + } + else { /* direction == BONE_SELECT_CHILD */ + bPoseChannel *pchan_iter; + Bone *bone_child = NULL; + int pass; + + /* first pass, only connected bones (the logical direct child) */ + for (pass = 0; pass < 2 && (bone_child == NULL); pass++) { + for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) { + /* possible we have multiple children, some invisible */ + if (PBONE_SELECTABLE(arm, pchan_iter->bone)) { + if (pchan_iter->parent == pchan_act) { + if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) { + bone_child = pchan_iter->bone; + break; + } } } } } + + if (bone_child) { + arm->act_bone = bone_child; + + if (!add_to_sel) { + pchan_act->bone->flag &= ~BONE_SELECTED; + } + bone_child->flag |= BONE_SELECTED; + + changed = true; + } } - CTX_DATA_END; - if (found == 0) + if (changed == false) { return OPERATOR_CANCELLED; + } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 5f9f24d23a4..1a1108a2b1c 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -43,6 +43,7 @@ #include "BKE_context.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_unit.h" #include "RNA_access.h" #include "RNA_define.h" @@ -53,6 +54,7 @@ #include "ED_armature.h" #include "ED_keyframes_draw.h" #include "ED_markers.h" +#include "ED_numinput.h" #include "ED_screen.h" #include "armature_intern.h" @@ -98,6 +100,8 @@ typedef struct tPoseSlideOp { int flag; /* unused for now, but can later get used for storing runtime settings.... */ float percentage; /* 0-1 value for determining the influence of whatever is relevant */ + + NumInput num; /* numeric input */ } tPoseSlideOp; /* Pose Sliding Modes */ @@ -154,6 +158,12 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode) */ BLI_dlrbTree_init(&pso->keys); + /* initialise numeric input */ + initNumInput(&pso->num); + pso->num.idx_max = 0; /* one axis */ + pso->num.val_flag[0] |= NUM_NO_NEGATIVE; + pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */ + /* return status is whether we've got all the data we were requested to get */ return 1; } @@ -201,6 +211,12 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) /* next/end */ eVal = evaluate_fcurve(fcu, (float)pso->nextFrame); + /* if both values are equal, don't do anything */ + if (IS_EQF(sVal, eVal)) { + (*val) = sVal; + return; + } + /* calculate the relative weights of the endpoints */ if (pso->mode == POSESLIDE_BREAKDOWN) { /* get weights from the percentage control */ @@ -234,7 +250,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) * - perform this weighting a number of times given by the percentage... */ int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ - + while (iters-- > 0) { (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f; } @@ -247,7 +263,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) * - perform this weighting a number of times given by the percentage... */ int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ - + while (iters-- > 0) { (*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f; } @@ -320,6 +336,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) if (prop) { switch (RNA_property_type(prop)) { + /* continuous values that can be smoothly interpolated... */ case PROP_FLOAT: { float tval = RNA_property_float_get(&ptr, prop); @@ -327,8 +344,6 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) RNA_property_float_set(&ptr, prop, tval); break; } - case PROP_BOOLEAN: - case PROP_ENUM: case PROP_INT: { float tval = (float)RNA_property_int_get(&ptr, prop); @@ -336,6 +351,23 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) RNA_property_int_set(&ptr, prop, (int)tval); break; } + + /* values which can only take discrete values */ + case PROP_BOOLEAN: + { + float tval = (float)RNA_property_boolean_get(&ptr, prop); + pose_slide_apply_val(pso, fcu, &tval); + RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here? + break; + } + case PROP_ENUM: + { + /* don't handle this case - these don't usually represent interchangeable + * set of values which should be interpolated between + */ + break; + } + default: /* cannot handle */ //printf("Cannot Pose Slide non-numerical property\n"); @@ -404,11 +436,11 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) } else if (pso->mode == POSESLIDE_PUSH) { float quat_diff[4], quat_orig[4]; - + /* calculate the delta transform from the previous to the current */ /* TODO: investigate ways to favour one transform more? */ sub_qt_qtqt(quat_diff, pchan->quat, quat_prev); - + /* make a copy of the original rotation */ copy_qt_qt(quat_orig, pchan->quat); @@ -418,7 +450,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) else { float quat_interp[4], quat_orig[4]; int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ - + /* perform this blending several times until a satisfactory result is reached */ while (iters-- > 0) { /* calculate the interpolation between the endpoints */ @@ -512,7 +544,7 @@ static void pose_slide_reset(tPoseSlideOp *pso) /* draw percentage indicator in header */ static void pose_slide_draw_status(tPoseSlideOp *pso) { - char status_str[32]; + char status_str[256]; char mode_str[32]; switch (pso->mode) { @@ -532,7 +564,18 @@ static void pose_slide_draw_status(tPoseSlideOp *pso) break; } - BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f)); + if (hasNumInput(&pso->num)) { + Scene *scene = pso->scene; + char str_offs[NUM_STR_REP_LEN]; + + outputNumInput(&pso->num, str_offs, &scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f)); + } + ED_area_headerprint(pso->sa, status_str); } @@ -617,6 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso = op->customdata; wmWindow *win = CTX_wm_window(C); + const bool has_numinput = hasNumInput(&pso->num); switch (event->type) { case LEFTMOUSE: /* confirm */ @@ -656,25 +700,54 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: /* calculate new position */ { - /* calculate percentage based on position of mouse (we only use x-axis for now. - * since this is more convenient for users to do), and store new percentage value - */ - pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); - RNA_float_set(op->ptr, "percentage", pso->percentage); - - /* update percentage indicator in header */ - pose_slide_draw_status(pso); - - /* reset transforms (to avoid accumulation errors) */ - pose_slide_reset(pso); - - /* apply... */ - pose_slide_apply(C, pso); + /* only handle mousemove if not doing numinput */ + if (has_numinput == false) { + /* calculate percentage based on position of mouse (we only use x-axis for now. + * since this is more convenient for users to do), and store new percentage value + */ + pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); + RNA_float_set(op->ptr, "percentage", pso->percentage); + + /* update percentage indicator in header */ + pose_slide_draw_status(pso); + + /* reset transforms (to avoid accumulation errors) */ + pose_slide_reset(pso); + + /* apply... */ + pose_slide_apply(C, pso); + } break; } - default: /* unhandled event (maybe it was some view manip? */ - /* allow to pass through */ - return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; + default: + if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) { + float value; + + /* Grab percentage from numeric input, and store this new value for redo + * NOTE: users see ints, while internally we use a 0-1 float + */ + value = pso->percentage * 100.0f; + applyNumInput(&pso->num, &value); + + pso->percentage = value / 100.0f; + CLAMP(pso->percentage, 0.0f, 1.0f); + RNA_float_set(op->ptr, "percentage", pso->percentage); + + /* update percentage indicator in header */ + pose_slide_draw_status(pso); + + /* reset transforms (to avoid accumulation errors) */ + pose_slide_reset(pso); + + /* apply... */ + pose_slide_apply(C, pso); + break; + } + else { + /* unhandled event - maybe it was some view manip? */ + /* allow to pass through */ + return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; + } } /* still running... */ @@ -898,6 +971,8 @@ typedef enum ePosePropagate_Termination { /* stop when we run out of keyframes */ POSE_PROPAGATE_BEFORE_END, + /* only do on keyframes that are selected */ + POSE_PROPAGATE_SELECTED_KEYS, /* only do on the frames where markers are selected */ POSE_PROPAGATE_SELECTED_MARKERS } ePosePropagate_Termination; @@ -1137,6 +1212,11 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu, if (ce == NULL) continue; } + else if (mode == POSE_PROPAGATE_SELECTED_KEYS) { + /* only allow if this keyframe is already selected - skip otherwise */ + if (BEZSELECTED(bezt) == 0) + continue; + } /* just flatten handles, since values will now be the same either side... */ /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */ @@ -1219,12 +1299,20 @@ static int pose_propagate_exec(bContext *C, wmOperator *op) void POSE_OT_propagate(wmOperatorType *ot) { static EnumPropertyItem terminate_items[] = { - {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", "Propagate pose to all keyframes after current frame that don't change (Default behavior)"}, - {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", "Propagate pose to first keyframe following the current frame only"}, - {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", "Propagate pose to the last keyframe only (i.e. making action cyclic)"}, - {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", "Propagate pose to all keyframes between current frame and 'Frame' property"}, - {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", "Propagate pose to all keyframes from current frame until no more are found"}, - {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"}, + {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", + "Propagate pose to all keyframes after current frame that don't change (Default behavior)"}, + {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", + "Propagate pose to first keyframe following the current frame only"}, + {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", + "Propagate pose to the last keyframe only (i.e. making action cyclic)"}, + {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", + "Propagate pose to all keyframes between current frame and 'Frame' property"}, + {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", + "Propagate pose to all keyframes from current frame until no more are found"}, + {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes", + "Propagate pose to all selected keyframes"}, + {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", + "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"}, {0, NULL, 0, NULL, NULL}}; /* identifiers */ diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index fbf6dccdb38..01e16df9f08 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -320,7 +320,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo if (selOnly) paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED)); else - paste_ok = ((pchan != NULL)); + paste_ok = (pchan != NULL); /* continue? */ if (paste_ok) { |