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.
This commit is contained in:
Joshua Leung 2010-01-25 10:16:36 +00:00
parent 41499247db
commit 5844560ec2
6 changed files with 242 additions and 109 deletions

@ -419,6 +419,9 @@ class VIEW3D_MT_select_pose(bpy.types.Menu):
props.extend = True props.extend = True
props.direction = 'CHILD' props.direction = 'CHILD'
layout.separator()
layout.operator_menu_enum("pose.select_grouped", "type", text="Grouped")
layout.operator("object.select_pattern", text="Select Pattern...") layout.operator("object.select_pattern", text="Select Pattern...")
@ -988,6 +991,8 @@ class VIEW3D_MT_pose(bpy.types.Menu):
layout.operator("pose.flip_names") layout.operator("pose.flip_names")
layout.operator("pose.quaternions_flip")
layout.separator() layout.separator()
layout.operator_context = 'INVOKE_AREA' layout.operator_context = 'INVOKE_AREA'

@ -817,6 +817,7 @@ static float dtar_get_prop_val (ChannelDriver *driver, DriverTarget *dtar)
break; break;
} }
/* degrees to radians (since curves are stored in degrees, but drivers need radians) */
if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) { if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) {
value *= 180.0/M_PI; value *= 180.0/M_PI;
} }

@ -86,6 +86,7 @@ void POSE_OT_select_parent(struct wmOperatorType *ot);
void POSE_OT_select_hierarchy(struct wmOperatorType *ot); void POSE_OT_select_hierarchy(struct wmOperatorType *ot);
void POSE_OT_select_linked(struct wmOperatorType *ot); void POSE_OT_select_linked(struct wmOperatorType *ot);
void POSE_OT_select_constraint_target(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_add(struct wmOperatorType *ot);
void POSE_OT_group_remove(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_autoside_names(struct wmOperatorType *ot);
void POSE_OT_flip_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_flags_set(struct wmOperatorType *ot);
void POSE_OT_armature_layers(struct wmOperatorType *ot); void POSE_OT_armature_layers(struct wmOperatorType *ot);

@ -127,6 +127,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_select_hierarchy); WM_operatortype_append(POSE_OT_select_hierarchy);
WM_operatortype_append(POSE_OT_select_linked); WM_operatortype_append(POSE_OT_select_linked);
WM_operatortype_append(POSE_OT_select_constraint_target); 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_add);
WM_operatortype_append(POSE_OT_group_remove); 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_autoside_names);
WM_operatortype_append(POSE_OT_flip_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_flags_set);
WM_operatortype_append(POSE_OT_armature_layers); 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_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_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_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, 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); 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); 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_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_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); WM_keymap_add_item(keymap, "POSE_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);

@ -93,8 +93,6 @@
static int pupmenu() {return 0;} static int pupmenu() {return 0;}
static void error() {}; static void error() {};
static void BIF_undo_push() {} static void BIF_undo_push() {}
static void countall() {}
static void autokeyframe_pose_cb_func() {}
/* ************* XXX *************** */ /* ************* XXX *************** */
/* This function is used to indicate that a bone is selected and needs keyframes inserted */ /* 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; return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob); 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; ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* props */ /* props */
RNA_def_enum(ot->srna, "direction", direction_items, ot->prop= RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
BONE_SELECT_PARENT, "Direction", "");
RNA_def_boolean(ot->srna, "extend", 0, "Add to Selection", ""); 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) void pose_copy_menu(Scene *scene)
{ {
@ -1205,14 +1362,14 @@ static int pose_group_unassign_exec (bContext *C, wmOperator *op)
pose= ob->pose; pose= ob->pose;
arm= ob->data; 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... // NOTE: unfortunately, we cannot use the context-iterators here, since they might not be defined...
// CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) // CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
/* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */ /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
// NOTE: sync this view3d_context() in space_view3d.c // 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) && (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) { if (pchan->agrp_index) {
pchan->agrp_index= 0; pchan->agrp_index= 0;
done= 1; done= 1;
@ -1246,95 +1403,6 @@ void POSE_OT_group_unassign (wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 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) 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 */ static int pose_flip_quats_exec (bContext *C, wmOperator *op)
void pose_flipquats(Scene *scene)
{ {
Object *ob = OBACT; Scene *scene= CTX_data_scene(C);
bArmature *arm= ob->data; Object *ob= CTX_data_active_object(C);
bPoseChannel *pchan;
if(ob->pose==NULL) bCommonKeySrc cks;
return; ListBase dsources = {&cks, &cks};
/* find sel bones */ /* init common-key-source for use by KeyingSets */
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { memset(&cks, 0, sizeof(bCommonKeySrc));
if(pchan->bone && (pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) { 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 */ /* quaternions have 720 degree range */
pchan->quat[0]= -pchan->quat[0]; pchan->quat[0]= -pchan->quat[0];
pchan->quat[1]= -pchan->quat[1]; pchan->quat[1]= -pchan->quat[1];
pchan->quat[2]= -pchan->quat[2]; pchan->quat[2]= -pchan->quat[2];
pchan->quat[3]= -pchan->quat[3]; 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;
/* 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;
} }
/* do autokey */ void POSE_OT_quaternions_flip (wmOperatorType *ot)
autokeyframe_pose_cb_func(ob, TFM_ROTATION, 0); {
/* 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 */ /* context: active channel */
void pose_special_editmenu(Scene *scene) void pose_special_editmenu(Scene *scene)
{ {