From 5844560ec2384f2e1208fdd6c2298df048c18461 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 25 Jan 2010 10:16:36 +0000 Subject: Restored missing PoseMode Operators: * Select Grouped Selects bones in the same layer or same group as the selected ones. Optimised the code for the select same groups too. * Flip Quats Flips quaternion values so that the rotation progresses over a different path while maintaining the same endpoint orientations. --- source/blender/editors/armature/armature_intern.h | 3 + source/blender/editors/armature/armature_ops.c | 6 + source/blender/editors/armature/poseobject.c | 334 +++++++++++++++------- 3 files changed, 235 insertions(+), 108 deletions(-) (limited to 'source/blender/editors/armature') diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index c65d4637dcf..5a1f8f35d62 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -86,6 +86,7 @@ void POSE_OT_select_parent(struct wmOperatorType *ot); void POSE_OT_select_hierarchy(struct wmOperatorType *ot); void POSE_OT_select_linked(struct wmOperatorType *ot); void POSE_OT_select_constraint_target(struct wmOperatorType *ot); +void POSE_OT_select_grouped(struct wmOperatorType *ot); void POSE_OT_group_add(struct wmOperatorType *ot); void POSE_OT_group_remove(struct wmOperatorType *ot); @@ -99,6 +100,8 @@ void POSE_OT_paths_clear(struct wmOperatorType *ot); void POSE_OT_autoside_names(struct wmOperatorType *ot); void POSE_OT_flip_names(struct wmOperatorType *ot); +void POSE_OT_quaternions_flip(struct wmOperatorType *ot); + void POSE_OT_flags_set(struct wmOperatorType *ot); void POSE_OT_armature_layers(struct wmOperatorType *ot); diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index a3c35413680..5f90f6eb745 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -127,6 +127,7 @@ void ED_operatortypes_armature(void) WM_operatortype_append(POSE_OT_select_hierarchy); WM_operatortype_append(POSE_OT_select_linked); WM_operatortype_append(POSE_OT_select_constraint_target); + WM_operatortype_append(POSE_OT_select_grouped); WM_operatortype_append(POSE_OT_group_add); WM_operatortype_append(POSE_OT_group_remove); @@ -139,6 +140,8 @@ void ED_operatortypes_armature(void) WM_operatortype_append(POSE_OT_autoside_names); WM_operatortype_append(POSE_OT_flip_names); + WM_operatortype_append(POSE_OT_quaternions_flip); + WM_operatortype_append(POSE_OT_flags_set); WM_operatortype_append(POSE_OT_armature_layers); @@ -290,6 +293,8 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "POSE_OT_loc_clear", GKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "POSE_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "POSE_OT_quaternions_flip", FKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "POSE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); kmi= WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); @@ -313,6 +318,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "extend", 1); WM_keymap_add_item(keymap, "POSE_OT_select_linked", LKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "POSE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "POSE_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); WM_keymap_add_item(keymap, "POSE_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 03e25bb67b8..7799c6e6e89 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -93,8 +93,6 @@ static int pupmenu() {return 0;} static void error() {}; static void BIF_undo_push() {} -static void countall() {} -static void autokeyframe_pose_cb_func() {} /* ************* XXX *************** */ /* This function is used to indicate that a bone is selected and needs keyframes inserted */ @@ -488,7 +486,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) } } - if(!found) + if (found == 0) return OPERATOR_CANCELLED; WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob); @@ -516,12 +514,171 @@ void POSE_OT_select_hierarchy(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* props */ - RNA_def_enum(ot->srna, "direction", direction_items, - BONE_SELECT_PARENT, "Direction", ""); + ot->prop= RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", ""); RNA_def_boolean(ot->srna, "extend", 0, "Add to Selection", ""); } +/* ******************* select grouped operator ************* */ + +static short pose_select_same_group (Object *ob, short extend) +{ + bPose *pose= (ob)? ob->pose : NULL; + bArmature *arm= (ob)? ob->data : NULL; + bPoseChannel *pchan; + char *group_flags; + int numGroups = 0; + short changed=0, tagged=0; + + /* sanity checks */ + if (ELEM3(NULL, ob, pose, arm)) + return 0; + + /* count the number of groups */ + numGroups= BLI_countlist(&pose->agroups); + if (numGroups == 0) + return 0; + + /* alloc a small array to keep track of the groups to use + * - each cell stores on/off state for whether group should be used + * - size is numGroups + 1, since index=0 is used for no-group + */ + group_flags= MEM_callocN(numGroups+1, "pose_select_same_group"); + + for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { + if (arm->layer & pchan->bone->layer) { + /* keep track of group as group to use later? */ + if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone)) { + group_flags[pchan->agrp_index] = 1; + tagged= 1; + } + + /* deselect all bones before selecting new ones? */ + if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) + pchan->bone->flag &= ~BONE_SELECTED; + } + } + + /* small optimisation: only loop through bones a second time if there are any groups tagged */ + if (tagged) { + /* only if group matches (and is not selected or current bone) */ + for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { + if ((arm->layer & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) { + /* check if the group used by this bone is counted */ + if (group_flags[pchan->agrp_index]) { + pchan->bone->flag |= BONE_SELECTED; + changed= 1; + } + } + } + } + + /* free temp info */ + MEM_freeN(group_flags); + + return changed; +} + +static short pose_select_same_layer (Object *ob, short extend) +{ + bPose *pose= (ob)? ob->pose : NULL; + bArmature *arm= (ob)? ob->data : NULL; + bPoseChannel *pchan; + short changed= 0; + int layers= 0; + + if (ELEM3(NULL, ob, pose, arm)) + return 0; + + /* figure out what bones are selected */ + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if (arm->layer & pchan->bone->layer) { + /* keep track of layers to use later? */ + if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone)) + layers |= pchan->bone->layer; + + /* deselect all bones before selecting new ones? */ + if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) + pchan->bone->flag &= ~BONE_SELECTED; + } + } + if (layers == 0) + return 0; + + /* select bones that are on same layers as layers flag */ + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if (arm->layer & pchan->bone->layer) { + /* if bone is on a suitable layer, and the bone can have its selection changed, select it */ + if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) { + pchan->bone->flag |= BONE_SELECTED; + changed= 1; + } + } + } + + return changed; +} + + +static int pose_select_grouped_exec (bContext *C, wmOperator *op) +{ + Object *ob= CTX_data_active_object(C); + short extend= RNA_boolean_get(op->ptr, "extend"); + short changed = 0; + + /* sanity check */ + if (ELEM(NULL, ob, ob->pose)) + return OPERATOR_CANCELLED; + + /* selection types + * NOTE: for the order of these, see the enum in POSE_OT_select_grouped() + */ + switch (RNA_enum_get(op->ptr, "type")) { + case 1: /* group */ + changed= pose_select_same_group(ob, extend); + break; + default: /* layer */ + changed= pose_select_same_layer(ob, extend); + break; + } + + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); + + /* report done status */ + if (changed) + return OPERATOR_FINISHED; + else + return OPERATOR_CANCELLED; +} + +void POSE_OT_select_grouped (wmOperatorType *ot) +{ + static EnumPropertyItem prop_select_grouped_types[] = { + {0, "LAYER", 0, "Layer", "Shared layers"}, + {1, "GROUP", 0, "Group", "Shared group"}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name= "Select Grouped"; + ot->description = "Select all visible bones grouped by various properties."; + ot->idname= "POSE_OT_select_grouped"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= pose_select_grouped_exec; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first."); + ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); +} + +/* ********************************************** */ void pose_copy_menu(Scene *scene) { @@ -1205,14 +1362,14 @@ static int pose_group_unassign_exec (bContext *C, wmOperator *op) pose= ob->pose; arm= ob->data; - /* add selected bones to ungroup then */ + /* find selected bones to remove from all bone groups */ // NOTE: unfortunately, we cannot use the context-iterators here, since they might not be defined... // CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */ // NOTE: sync this view3d_context() in space_view3d.c if ((pchan->bone) && (arm->layer & pchan->bone->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) { - if (pchan->bone->flag & BONE_SELECTED || pchan->bone == arm->act_bone) { + if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone)) { if (pchan->agrp_index) { pchan->agrp_index= 0; done= 1; @@ -1246,95 +1403,6 @@ void POSE_OT_group_unassign (wmOperatorType *ot) ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } -static short pose_select_same_group (Object *ob) -{ - bPose *pose= (ob)? ob->pose : NULL; - bArmature *arm= (ob)? ob->data : NULL; - bPoseChannel *pchan, *chan; - short changed= 0; - - if (ELEM3(NULL, ob, pose, arm)) - return 0; - - /* loop in loop... bad and slow! */ - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if (arm->layer & pchan->bone->layer) { - if (pchan->bone->flag & BONE_SELECTED || pchan->bone == arm->act_bone) { - - /* only if group matches (and is not selected or current bone) */ - for (chan= ob->pose->chanbase.first; chan; chan= chan->next) { - if (arm->layer & chan->bone->layer) { - if (pchan->agrp_index == chan->agrp_index) { - chan->bone->flag |= BONE_SELECTED; - changed= 1; - } - } - } - - } - } - } - - return changed; -} - -static short pose_select_same_layer (Object *ob) -{ - bPose *pose= (ob)? ob->pose : NULL; - bArmature *arm= (ob)? ob->data : NULL; - bPoseChannel *pchan; - int layers= 0, changed= 0; - - if (ELEM3(NULL, ob, pose, arm)) - return 0; - - /* figure out what bones are selected */ - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if (arm->layer & pchan->bone->layer) { - if (pchan->bone->flag & BONE_SELECTED || pchan->bone == arm->act_bone) { - layers |= pchan->bone->layer; - } - } - } - if (layers == 0) - return 0; - - /* select bones that are on same layers as layers flag */ - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if (arm->layer & pchan->bone->layer) { - if (layers & pchan->bone->layer) { - pchan->bone->flag |= BONE_SELECTED; - changed= 1; - } - } - } - - return changed; -} - -void pose_select_grouped (Scene *scene, short nr) -{ - short changed = 0; - - if (nr == 1) changed= pose_select_same_group(OBACT); - else if (nr == 2) changed= pose_select_same_layer(OBACT); - - if (changed) { - countall(); - BIF_undo_push("Select Grouped"); - } -} - -/* Shift-G in 3D-View while in PoseMode */ -void pose_select_grouped_menu (Scene *scene) -{ - short nr; - - /* here we go */ - nr= pupmenu("Select Grouped%t|In Same Group%x1|In Same Layer%x2"); - pose_select_grouped(scene, nr); -} - /* ********************************************** */ static int pose_flip_names_exec (bContext *C, wmOperator *op) @@ -1714,31 +1782,81 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot) /* ********************************************** */ -/* for use in insertkey, ensure rotation goes other way around */ -void pose_flipquats(Scene *scene) +static int pose_flip_quats_exec (bContext *C, wmOperator *op) { - Object *ob = OBACT; - bArmature *arm= ob->data; - bPoseChannel *pchan; + Scene *scene= CTX_data_scene(C); + Object *ob= CTX_data_active_object(C); - if(ob->pose==NULL) - return; + bCommonKeySrc cks; + ListBase dsources = {&cks, &cks}; - /* find sel bones */ - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if(pchan->bone && (pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) { + /* init common-key-source for use by KeyingSets */ + memset(&cks, 0, sizeof(bCommonKeySrc)); + cks.id= &ob->id; + + /* loop through all selected pchans, flipping and keying (as needed) */ + CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) + { + /* only if bone is using quaternion rotation */ + if (pchan->rotmode == ROT_MODE_QUAT) { /* quaternions have 720 degree range */ pchan->quat[0]= -pchan->quat[0]; pchan->quat[1]= -pchan->quat[1]; pchan->quat[2]= -pchan->quat[2]; pchan->quat[3]= -pchan->quat[3]; + + /* perform auto-keying + * NOTE: paths don't need recalculation here, since the orientations shouldn't have changed + */ + if (autokeyframe_cfra_can_key(scene, &ob->id)) { + /* Set keys on pose + * - KeyingSet to use depends on rotation mode + * (but that's handled by the templates code) + */ + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); + + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + + /* clear any unkeyed tags */ + if (pchan->bone) + pchan->bone->flag &= ~BONE_UNKEYED; + } + else { + /* add unkeyed tags */ + if (pchan->bone) + pchan->bone->flag |= BONE_UNKEYED; + } } } + CTX_DATA_END; - /* do autokey */ - autokeyframe_pose_cb_func(ob, TFM_ROTATION, 0); + /* notifiers and updates */ + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); + + return OPERATOR_FINISHED; } +void POSE_OT_quaternions_flip (wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flip Quats"; + ot->idname= "POSE_OT_quaternions_flip"; + ot->description= "Flip quaternion values to achieve desired rotations, while maintaining the same orientations."; + + /* callbacks */ + ot->exec= pose_flip_quats_exec; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ********************************************** */ + /* context: active channel */ void pose_special_editmenu(Scene *scene) { -- cgit v1.2.3