Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiao Xiangquan <xiaoxiangquan@gmail.com>2011-09-01 19:08:32 +0400
committerXiao Xiangquan <xiaoxiangquan@gmail.com>2011-09-01 19:08:32 +0400
commit981f7fcd0d315abb425bf34dd37f7cd4d9e8d55e (patch)
tree70800c93ec1a12579c32874e2a72eaf3290eba8e /source/blender/editors/armature
parent5b91a783cf0ec132398a2767d3419d675e5126b5 (diff)
parent2365c64014b3e067bb212b2061f1d14c1f944090 (diff)
merge with trunk r39834
Diffstat (limited to 'source/blender/editors/armature')
-rw-r--r--source/blender/editors/armature/SConscript2
-rw-r--r--source/blender/editors/armature/armature_intern.h7
-rw-r--r--source/blender/editors/armature/armature_ops.c9
-rw-r--r--source/blender/editors/armature/editarmature.c82
-rw-r--r--source/blender/editors/armature/poseSlide.c47
-rw-r--r--source/blender/editors/armature/poseUtils.c11
-rw-r--r--source/blender/editors/armature/poselib.c63
-rw-r--r--source/blender/editors/armature/poseobject.c687
8 files changed, 650 insertions, 258 deletions
diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript
index d790a392407..ded82b3dfb7 100644
--- a/source/blender/editors/armature/SConscript
+++ b/source/blender/editors/armature/SConscript
@@ -7,7 +7,7 @@ incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../gpu ../../makesrna #/intern/opennl/extern'
-if env['OURPLATFORM'] == 'linux2':
+if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 85da7a212c9..47123b7fb4d 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -95,6 +93,7 @@ void POSE_OT_rot_clear(struct wmOperatorType *ot);
void POSE_OT_loc_clear(struct wmOperatorType *ot);
void POSE_OT_scale_clear(struct wmOperatorType *ot);
void POSE_OT_transforms_clear(struct wmOperatorType *ot);
+void POSE_OT_user_transforms_clear(struct wmOperatorType *ot);
void POSE_OT_copy(struct wmOperatorType *ot);
void POSE_OT_paste(struct wmOperatorType *ot);
@@ -110,6 +109,8 @@ void POSE_OT_select_flip_active(struct wmOperatorType *ot);
void POSE_OT_group_add(struct wmOperatorType *ot);
void POSE_OT_group_remove(struct wmOperatorType *ot);
+void POSE_OT_group_move(struct wmOperatorType *ot);
+void POSE_OT_group_sort(struct wmOperatorType *ot);
void POSE_OT_group_assign(struct wmOperatorType *ot);
void POSE_OT_group_unassign(struct wmOperatorType *ot);
void POSE_OT_group_select(struct wmOperatorType *ot);
@@ -121,6 +122,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_rotation_mode_set(struct wmOperatorType *ot);
+
void POSE_OT_quaternions_flip(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 88393f97077..6369f9280e6 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -111,6 +109,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_loc_clear);
WM_operatortype_append(POSE_OT_scale_clear);
WM_operatortype_append(POSE_OT_transforms_clear);
+ WM_operatortype_append(POSE_OT_user_transforms_clear);
WM_operatortype_append(POSE_OT_copy);
WM_operatortype_append(POSE_OT_paste);
@@ -127,6 +126,8 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_group_add);
WM_operatortype_append(POSE_OT_group_remove);
+ WM_operatortype_append(POSE_OT_group_move);
+ WM_operatortype_append(POSE_OT_group_sort);
WM_operatortype_append(POSE_OT_group_assign);
WM_operatortype_append(POSE_OT_group_unassign);
WM_operatortype_append(POSE_OT_group_select);
@@ -137,6 +138,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_rotation_mode_set);
WM_operatortype_append(POSE_OT_quaternions_flip);
@@ -309,6 +312,8 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "POSE_OT_quaternions_flip", FKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "POSE_OT_rotation_mode_set", RKEY, 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);
kmi= WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
index b0432d980dc..3709c672ec0 100644
--- a/source/blender/editors/armature/editarmature.c
+++ b/source/blender/editors/armature/editarmature.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -496,15 +494,32 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4])
EditBone *ebone;
bArmature *arm= ob->data;
float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
-
+ float mat3[3][3];
+
+ copy_m3_m4(mat3, mat);
+ normalize_m3(mat3);
+
/* Put the armature into editmode */
ED_armature_to_edit(ob);
/* Do the rotations */
- for (ebone = arm->edbo->first; ebone; ebone=ebone->next){
+ for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
+ float delta[3], tmat[3][3];
+
+ /* find the current bone's roll matrix */
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, tmat);
+
+ /* transform the roll matrix */
+ mul_m3_m3m3(tmat, mat3, tmat);
+
+ /* transform the bone */
mul_m4_v3(mat, ebone->head);
mul_m4_v3(mat, ebone->tail);
-
+
+ /* apply the transfiormed roll back */
+ mat3_to_vec_roll(tmat, NULL, &ebone->roll);
+
ebone->rad_head *= scale;
ebone->rad_tail *= scale;
ebone->dist *= scale;
@@ -2993,28 +3008,31 @@ static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone
/* TODO, copy more things to the new bone */
newbone->flag= start->flag & (BONE_HINGE|BONE_NO_DEFORM|BONE_NO_SCALE|BONE_NO_CYCLICOFFSET|BONE_NO_LOCAL_LOCATION|BONE_DONE);
- /* step 2a: parent children of in-between bones to newbone */
- for (chain= chains->first; chain; chain= chain->next) {
- /* ick: we need to check if parent of each bone in chain is one of the bones in the */
- short found= 0;
- for (ebo= chain->data; ebo; ebo= ebo->parent) {
+ /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
+ * - potentially several tips for side chains leading to some tree exist...
+ */
+ for (chain = chains->first; chain; chain = chain->next) {
+ /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
+ * merging (need to stop in this case to avoid corrupting this chain too!)
+ */
+ for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
+ short found = 0;
- /* try to find which bone from the list to be removed, is the parent */
- for (ebone= end; ebone; ebone= ebone->parent) {
- if (ebo->parent == ebone) {
- found= 1;
+ /* check if this bone is parented to one in the merging chain
+ * ! WATCHIT: must only go check until end of checking chain
+ */
+ for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
+ /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
+ if (ebone->parent == ebo) {
+ ebone->parent = newbone;
+ found = 1;
break;
}
}
- /* adjust this bone's parent to newbone then */
- if (found) {
- ebo->parent= newbone;
+ /* carry on to the next tip now */
+ if (found)
break;
- }
- }
- if (found) {
- break;
}
}
@@ -3050,12 +3068,12 @@ static int armature_merge_exec (bContext *C, wmOperator *op)
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;
-
- armature_tag_select_mirrored(arm);
-
+
/* each 'chain' is the last bone in the chain (with no children) */
for (chain= chains.first; chain; chain= nchain) {
EditBone *bstart= NULL, *bend= NULL;
@@ -3100,7 +3118,7 @@ static int armature_merge_exec (bContext *C, wmOperator *op)
}
armature_tag_unselect(arm);
-
+
BLI_freelistN(&chains);
}
@@ -5404,12 +5422,14 @@ void ED_armature_bone_rename(bArmature *arm, char *oldnamep, char *newnamep)
ScrArea *sa;
/* add regions */
for(sa= screen->areabase.first; sa; sa= sa->next) {
- SpaceLink *sl= sa->spacedata.first;
- if(sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d= (View3D *)sl;
- if(v3d->ob_centre && v3d->ob_centre->data == arm) {
- if (!strcmp(v3d->ob_centre_bone, oldname)) {
- BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(v3d->ob_centre && v3d->ob_centre->data == arm) {
+ if (!strcmp(v3d->ob_centre_bone, oldname)) {
+ BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
+ }
}
}
}
diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c
index 2ec91cca250..1ee0c3c64ac 100644
--- a/source/blender/editors/armature/poseSlide.c
+++ b/source/blender/editors/armature/poseSlide.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -95,7 +93,8 @@
/* Temporary data shared between these operators */
typedef struct tPoseSlideOp {
Scene *scene; /* current scene */
- ARegion *ar; /* region that we're operating in (needed for */
+ ScrArea *sa; /* area that we're operating in (needed for modal()) */
+ ARegion *ar; /* region that we're operating in (needed for modal()) */
Object *ob; /* active object that Pose Info comes from */
bArmature *arm; /* armature for pose */
@@ -134,6 +133,7 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode)
pso->scene= CTX_data_scene(C);
pso->ob= ED_object_pose_armature(CTX_data_active_object(C));
pso->arm= (pso->ob)? pso->ob->data : NULL;
+ pso->sa= CTX_wm_area(C); /* only really needed when doing modal() */
pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */
pso->cframe= pso->scene->r.cfra;
@@ -521,6 +521,33 @@ static void pose_slide_reset (tPoseSlideOp *pso)
/* ------------------------------------ */
+/* draw percentage indicator in header */
+static void pose_slide_draw_status (tPoseSlideOp *pso)
+{
+ char statusStr[32];
+ char mode[32];
+
+ switch (pso->mode) {
+ case POSESLIDE_PUSH:
+ strcpy(mode, "Push Pose");
+ break;
+ case POSESLIDE_RELAX:
+ strcpy(mode, "Relax Pose");
+ break;
+ case POSESLIDE_BREAKDOWN:
+ strcpy(mode, "Breakdown");
+ break;
+
+ default:
+ // unknown
+ strcpy(mode, "Sliding-Tool");
+ break;
+ }
+
+ sprintf(statusStr, "%s: %d %%", mode, (int)(pso->percentage*100.0f));
+ ED_area_headerprint(pso->sa, statusStr);
+}
+
/* common code for invoke() methods */
static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
@@ -589,6 +616,9 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *
/* set cursor to indicate modal */
WM_cursor_modal(win, BC_EW_SCROLLCURSOR);
+ /* header print */
+ pose_slide_draw_status(pso);
+
/* add a modal handler for this operator */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -603,7 +633,8 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
switch (evt->type) {
case LEFTMOUSE: /* confirm */
{
- /* return to normal cursor */
+ /* return to normal cursor and header status */
+ ED_area_headerprint(pso->sa, NULL);
WM_cursor_restore(win);
/* insert keyframes as required... */
@@ -617,7 +648,8 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
case ESCKEY: /* cancel */
case RIGHTMOUSE:
{
- /* return to normal cursor */
+ /* return to normal cursor and header status */
+ ED_area_headerprint(pso->sa, NULL);
WM_cursor_restore(win);
/* reset transforms back to original state */
@@ -641,6 +673,9 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
pso->percentage= (evt->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);
@@ -1002,7 +1037,7 @@ static short pose_propagate_get_refVal (Object *ob, FCurve *fcu, float *value)
/* resolve the property... */
if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) {
- if (RNA_property_array_check(&ptr, prop)) {
+ if (RNA_property_array_check(prop)) {
/* array */
if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
found= TRUE;
diff --git a/source/blender/editors/armature/poseUtils.c b/source/blender/editors/armature/poseUtils.c
index 3c74a816fdb..4b22d76ad0b 100644
--- a/source/blender/editors/armature/poseUtils.c
+++ b/source/blender/editors/armature/poseUtils.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -247,6 +245,15 @@ void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListB
/* insert keyframes for all relevant bones in one go */
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
BLI_freelistN(&dsources);
+
+ /* do the bone paths
+ * - only do this if keyframes should have been added
+ * - do not calculate unless there are paths already to update...
+ */
+ if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
+ ED_pose_recalculate_paths(scene, ob);
+ }
}
}
diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c
index dc47ad1a1e1..1d6ec1685b2 100644
--- a/source/blender/editors/armature/poselib.c
+++ b/source/blender/editors/armature/poselib.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -112,22 +110,34 @@ static int poselib_get_free_index (bAction *act)
{
TimeMarker *marker;
int low=0, high=0;
+ short changed = 0;
/* sanity checks */
if (ELEM(NULL, act, act->markers.first)) return 1;
- /* loop over poses finding various values (poses are not stored in chronological order) */
- for (marker= act->markers.first; marker; marker= marker->next) {
- /* only increase low if value is 1 greater than low, to find "gaps" where
- * poses were removed from the poselib
- */
- if (marker->frame == (low + 1))
- low++;
+ /* As poses are not stored in chronological order, we must iterate over this list
+ * a few times until we don't make any new discoveries (mostly about the lower bound).
+ * Prevents problems with deleting then trying to add new poses [#27412]
+ */
+ do {
+ changed = 0;
- /* value replaces high if it is the highest value encountered yet */
- if (marker->frame > high)
- high= marker->frame;
- }
+ for (marker= act->markers.first; marker; marker= marker->next) {
+ /* only increase low if value is 1 greater than low, to find "gaps" where
+ * poses were removed from the poselib
+ */
+ if (marker->frame == (low + 1)) {
+ low++;
+ changed = 1;
+ }
+
+ /* value replaces high if it is the highest value encountered yet */
+ if (marker->frame > high) {
+ high= marker->frame;
+ changed = 1;
+ }
+ }
+ } while (changed != 0);
/* - if low is not equal to high, then low+1 is a gap
* - if low is equal to high, then high+1 is the next index (add at end)
@@ -333,6 +343,11 @@ static int poselib_sanitise_exec (bContext *C, wmOperator *op)
/* free temp memory */
BLI_dlrbTree_free(&keys);
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
+
return OPERATOR_FINISHED;
}
@@ -557,6 +572,11 @@ static int poselib_remove_exec (bContext *C, wmOperator *op)
/* fix active pose number */
act->active_marker= 0;
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
+
/* done */
return OPERATOR_FINISHED;
}
@@ -639,6 +659,11 @@ static int poselib_rename_exec (bContext *C, wmOperator *op)
BLI_strncpy(marker->name, newname, sizeof(marker->name));
BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name));
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
+
/* done */
return OPERATOR_FINISHED;
}
@@ -842,7 +867,7 @@ static void poselib_apply_pose (tPoseLib_PreviewData *pld)
/* start applying - only those channels which have a key at this point in time! */
for (agrp= act->groups.first; agrp; agrp= agrp->next) {
/* check if group has any keyframes */
- if (ANIM_animchanneldata_keyframes_loop(&ked, agrp, ALE_GROUP, NULL, group_ok_cb, NULL, 0)) {
+ if (ANIM_animchanneldata_keyframes_loop(&ked, NULL, agrp, ALE_GROUP, NULL, group_ok_cb, NULL)) {
/* has keyframe on this frame, so try to get a PoseChannel with this name */
pchan= get_pose_channel(pose, agrp->name);
@@ -883,11 +908,11 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData
/* start tagging/keying */
for (agrp= act->groups.first; agrp; agrp= agrp->next) {
- /* only for selected action channels */
- if (agrp->flag & AGRP_SELECTED) {
- pchan= get_pose_channel(pose, agrp->name);
-
- if (pchan) {
+ /* only for selected bones unless there aren't any selected, in which case all are included */
+ pchan= get_pose_channel(pose, agrp->name);
+
+ if (pchan) {
+ if ( (pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) ) {
if (autokey) {
/* add datasource override for the PoseChannel, to be used later */
ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan);
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
index cd632333ce7..da66d6fcfbb 100644
--- a/source/blender/editors/armature/poseobject.c
+++ b/source/blender/editors/armature/poseobject.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -51,6 +49,7 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "BKE_animsys.h"
#include "BKE_anim.h"
#include "BKE_idprop.h"
#include "BKE_action.h"
@@ -66,6 +65,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -110,24 +110,6 @@ Object *ED_object_pose_armature(Object *ob)
return NULL;
}
-
-/* This function is used to indicate that a bone is selected and needs keyframes inserted */
-static void set_pose_keys (Object *ob)
-{
- bArmature *arm= ob->data;
- bPoseChannel *chan;
-
- if (ob->pose){
- for (chan=ob->pose->chanbase.first; chan; chan=chan->next){
- Bone *bone= chan->bone;
- if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
- chan->flag |= POSE_KEY;
- else
- chan->flag &= ~POSE_KEY;
- }
- }
-}
-
/* This function is used to process the necessary updates for */
void ED_armature_enter_posemode(bContext *C, Base *base)
{
@@ -606,6 +588,63 @@ static short pose_select_same_layer (bContext *C, Object *ob, short extend)
return changed;
}
+static int pose_select_same_keyingset(bContext *C, Object *ob, short extend)
+{
+ KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
+ KS_Path *ksp;
+
+ bArmature *arm = (ob)? ob->data : NULL;
+ bPose *pose= (ob)? ob->pose : NULL;
+ short changed= 0;
+
+ /* sanity checks: validate Keying Set and object */
+ if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
+ return 0;
+
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* if not extending selection, deselect all selected first */
+ if (extend == 0) {
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE)==0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+ }
+
+ /* iterate over elements in the Keying Set, setting selection depending on whether
+ * that bone is visible or not...
+ */
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+ /* only items related to this object will be relevant */
+ if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
+ if (strstr(ksp->rna_path, "bones")) {
+ char *boneName = BLI_getQuotedStr(ksp->rna_path, "bones[");
+
+ if (boneName) {
+ bPoseChannel *pchan = get_pose_channel(pose, boneName);
+
+ if (pchan) {
+ /* select if bone is visible and can be affected */
+ if ((PBONE_VISIBLE(arm, pchan->bone)) &&
+ (pchan->bone->flag & BONE_UNSELECTABLE)==0)
+ {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+
+ /* free temp memory */
+ MEM_freeN(boneName);
+ }
+ }
+ }
+ }
+
+ return changed;
+}
static int pose_select_grouped_exec (bContext *C, wmOperator *op)
{
@@ -624,6 +663,9 @@ static int pose_select_grouped_exec (bContext *C, wmOperator *op)
case 1: /* group */
changed= pose_select_same_group(C, ob, extend);
break;
+ case 2: /* Keying Set */
+ changed= pose_select_same_keyingset(C, ob, extend);
+ break;
default: /* layer */
changed= pose_select_same_layer(C, ob, extend);
break;
@@ -644,6 +686,7 @@ void POSE_OT_select_grouped (wmOperatorType *ot)
static EnumPropertyItem prop_select_grouped_types[] = {
{0, "LAYER", 0, N_("Layer"), N_("Shared layers")},
{1, "GROUP", 0, N_("Group"), N_("Shared group")},
+ {2, "KEYINGSET", 0, N_("Keying Set"), N_("All bones affected by active Keying Set")},
{0, NULL, 0, NULL, NULL}
};
@@ -947,6 +990,149 @@ void free_posebuf(void)
g_posebuf=NULL;
}
+/* This function is used to indicate that a bone is selected
+ * and needs to be included in copy buffer (used to be for inserting keys)
+ */
+static void set_pose_keys (Object *ob)
+{
+ bArmature *arm= ob->data;
+ bPoseChannel *chan;
+
+ if (ob->pose){
+ for (chan=ob->pose->chanbase.first; chan; chan=chan->next){
+ Bone *bone= chan->bone;
+ if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
+ chan->flag |= POSE_KEY;
+ else
+ chan->flag &= ~POSE_KEY;
+ }
+ }
+}
+
+/* perform paste pose, for a single bone
+ * < ob: object where bone to paste to lives
+ * < chan: bone that pose to paste comes from
+ * < selOnly: only paste on selected bones
+ * < flip: flip on x-axis
+ *
+ * > returns: whether the bone that we pasted to if we succeeded
+ */
+static bPoseChannel *pose_bone_do_paste (Object *ob, bPoseChannel *chan, short selOnly, short flip)
+{
+ bPoseChannel *pchan;
+ char name[32];
+ short paste_ok;
+
+ /* get the name - if flipping, we must flip this first */
+ if (flip)
+ flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
+ else
+ BLI_strncpy(name, chan->name, sizeof(name));
+
+ /* only copy when:
+ * 1) channel exists - poses are not meant to add random channels to anymore
+ * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
+ */
+ pchan= get_pose_channel(ob->pose, name);
+
+ if (selOnly)
+ paste_ok= ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ else
+ paste_ok= ((pchan != NULL));
+
+ /* continue? */
+ if (paste_ok) {
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ VECCOPY(pchan->loc, chan->loc);
+ VECCOPY(pchan->size, chan->size);
+ pchan->flag= chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ VECCOPY(pchan->eul, chan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ VECCOPY(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
+ }
+ else {
+ QUATCOPY(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE)
+ axis_angle_to_eulO( pchan->eul, pchan->rotmode,chan->rotAxis, chan->rotAngle);
+ else
+ quat_to_eulO( pchan->eul, pchan->rotmode,chan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0)
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ else
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0)
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
+ else
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0]*= -1;
+
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
+
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1]*= -1;
+ eul[2]*= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1]*= -1;
+ eul[2]*= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop= IDP_CopyProperty(chan->prop);
+ }
+ }
+ }
+
+ /* return whether paste went ahead */
+ return pchan;
+}
+
/* ---- */
static int pose_copy_exec (bContext *C, wmOperator *op)
@@ -989,9 +1175,9 @@ void POSE_OT_copy (wmOperatorType *ot)
static int pose_paste_exec (bContext *C, wmOperator *op)
{
- Scene *scene= CTX_data_scene(C);
Object *ob= ED_object_pose_armature(CTX_data_active_object(C));
- bPoseChannel *chan, *pchan;
+ Scene *scene= CTX_data_scene(C);
+ bPoseChannel *chan;
int flip= RNA_boolean_get(op->ptr, "flipped");
int selOnly= RNA_boolean_get(op->ptr, "selected_mask");
@@ -1004,120 +1190,22 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* if selOnly option is enabled, if user hasn't selected any bones,
+ * just go back to default behaviour to be more in line with other pose tools
+ */
+ if (selOnly) {
+ if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
+ selOnly = 0;
+ }
+
/* Safely merge all of the channels in the buffer pose into any existing pose */
for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) {
if (chan->flag & POSE_KEY) {
- char name[32];
- short paste_ok;
+ /* try to perform paste on this bone */
+ bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
- /* get the name - if flipping, we must flip this first */
- if (flip)
- flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
- else
- BLI_strncpy(name, chan->name, sizeof(name));
-
- /* only copy when:
- * 1) channel exists - poses are not meant to add random channels to anymore
- * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
- */
- pchan= get_pose_channel(ob->pose, name);
-
- if (selOnly)
- paste_ok= ((pchan) && (pchan->bone->flag & BONE_SELECTED));
- else
- paste_ok= ((pchan != NULL));
-
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- VECCOPY(pchan->loc, chan->loc);
- VECCOPY(pchan->size, chan->size);
- pchan->flag= chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- VECCOPY(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- VECCOPY(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- QUATCOPY(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE)
- axis_angle_to_eulO( pchan->eul, pchan->rotmode,chan->rotAxis, chan->rotAngle);
- else
- quat_to_eulO( pchan->eul, pchan->rotmode,chan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0)
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- else
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
- else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0)
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- else
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0]*= -1;
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
-
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1]*= -1;
- eul[2]*= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
-
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1]*= -1;
- eul[2]*= -1;
- eul_to_quat(pchan->quat, eul);
- }
- }
-
- /* ID properties
- * - only free the existing properties if the channel we're copying from has them
- * NOTE: this means that if the pose depends on some pchan property, the pose may not be ok,
- * but this is better than loosing all the setting you've painstakingly added...
- */
- if (chan->prop) {
- /* free the old properties since we want to replace them now */
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- pchan->prop= NULL;
- }
-
- /* now copy over the new copy of the properties */
- pchan->prop= IDP_CopyProperty(chan->prop);
- }
-
- /* keyframing tagging */
+ if (pchan) {
+ /* keyframing tagging for successful paste */
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
ListBase dsources = {NULL, NULL};
@@ -1171,11 +1259,11 @@ void POSE_OT_paste (wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "flipped", 0, _("Flipped on X-Axis"), _("Paste the stored pose flipped on to current pose"));
- RNA_def_boolean(ot->srna, "selected_mask", 0, _("On Selected Only"), _("Only paste the stored pose on to selected bones in the current pose"));
+ RNA_def_boolean(ot->srna, "selected_mask", 1, _("On Selected Only"), _("Only paste the stored pose on to selected bones in the current pose"));
}
/* ********************************************** */
-
+/* Bone Groups */
static int pose_group_add_exec (bContext *C, wmOperator *UNUSED(op))
{
@@ -1427,6 +1515,171 @@ void POSE_OT_group_unassign (wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
+static int group_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+ bPose *pose= (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ bActionGroup *grp;
+ int dir= RNA_enum_get(op->ptr, "direction");
+ int grpIndexA, grpIndexB;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* get group to move */
+ grp= BLI_findlink(&pose->agroups, pose->active_group-1);
+ if (grp == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* move bone group */
+ grpIndexA = pose->active_group;
+ if (dir == 1) { /* up */
+ void *prev = grp->prev;
+
+ if (prev == NULL)
+ return OPERATOR_FINISHED;
+
+ BLI_remlink(&pose->agroups, grp);
+ BLI_insertlinkbefore(&pose->agroups, prev, grp);
+
+ grpIndexB = grpIndexA - 1;
+ pose->active_group--;
+ }
+ else { /* down */
+ void *next = grp->next;
+
+ if (next == NULL)
+ return OPERATOR_FINISHED;
+
+ BLI_remlink(&pose->agroups, grp);
+ BLI_insertlinkafter(&pose->agroups, next, grp);
+
+ grpIndexB = grpIndexA + 1;
+ pose->active_group++;
+ }
+
+ /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->agrp_index == grpIndexB)
+ pchan->agrp_index= grpIndexA;
+ else if (pchan->agrp_index == grpIndexA)
+ pchan->agrp_index= grpIndexB;
+ }
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem group_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name= "Move Bone Group";
+ ot->idname= "POSE_OT_group_move";
+ ot->description= "Change position of active Bone Group in list of Bone Groups";
+
+ /* api callbacks */
+ ot->exec= group_move_exec;
+ ot->poll= ED_operator_posemode;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
+/* bone group sort element */
+typedef struct tSortActionGroup {
+ bActionGroup *agrp;
+ int index;
+} tSortActionGroup;
+
+/* compare bone groups by name */
+static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
+{
+ tSortActionGroup *sgrp_a= (tSortActionGroup *)sgrp_a_ptr;
+ tSortActionGroup *sgrp_b= (tSortActionGroup *)sgrp_b_ptr;
+
+ return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
+}
+
+static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+ bPose *pose= (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ tSortActionGroup *agrp_array;
+ bActionGroup *agrp;
+ int agrp_count;
+ int i;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* create temporary array with bone groups and indices */
+ agrp_count = BLI_countlist(&pose->agroups);
+ agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
+ for (agrp= pose->agroups.first, i= 0; agrp; agrp= agrp->next, i++) {
+ BLI_assert(i < agrp_count);
+ agrp_array[i].agrp = agrp;
+ agrp_array[i].index = i+1;
+ }
+
+ /* sort bone groups by name */
+ qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
+
+ /* create sorted bone group list from sorted array */
+ pose->agroups.first= pose->agroups.last= NULL;
+ for (i= 0; i < agrp_count; i++) {
+ BLI_addtail(&pose->agroups, agrp_array[i].agrp);
+ }
+
+ /* fix changed bone group indizes in bones */
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for (i= 0; i < agrp_count; i++) {
+ if (pchan->agrp_index == agrp_array[i].index) {
+ pchan->agrp_index= i+1;
+ break;
+ }
+ }
+ }
+
+ /* free temp resources */
+ MEM_freeN(agrp_array);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_sort(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Sort Bone Groups";
+ ot->idname= "POSE_OT_group_sort";
+ ot->description= "Sort Bone Groups by their names in ascending order";
+
+ /* api callbacks */
+ ot->exec= group_sort_exec;
+ ot->poll= ED_operator_posemode;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
static void pose_group_select(bContext *C, Object *ob, int select)
{
bPose *pose= ob->pose;
@@ -1627,6 +1880,46 @@ void POSE_OT_autoside_names (wmOperatorType *ot)
/* ********************************************** */
+static int pose_bone_rotmode_exec (bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ int mode = RNA_enum_get(op->ptr, "type");
+
+ /* set rotation mode of selected bones */
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ pchan->rotmode = mode;
+ }
+ CTX_DATA_END;
+
+ /* notifiers and updates */
+ DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_rotation_mode_set (wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Set Rotation Mode";
+ ot->idname= "POSE_OT_rotation_mode_set";
+ ot->description= "Set the rotation representation used by selected bones";
+
+ /* callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= pose_bone_rotmode_exec;
+ ot->poll= ED_operator_posemode;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop= RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
+}
+
+/* ********************************************** */
+
/* Show all armature layers */
static int pose_armature_layers_showall_poll (bContext *C)
{
@@ -1713,7 +2006,7 @@ static int pose_armature_layers_exec (bContext *C, wmOperator *op)
PointerRNA ptr;
int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- if(ob==NULL || ob->data==NULL) {
+ if (ELEM(NULL, ob, ob->data)) {
return OPERATOR_CANCELLED;
}
@@ -1917,6 +2210,7 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot)
}
/* ********************************************** */
+/* Flip Quats */
static int pose_flip_quats_exec (bContext *C, wmOperator *UNUSED(op))
{
@@ -1931,7 +2225,7 @@ static int pose_flip_quats_exec (bContext *C, wmOperator *UNUSED(op))
if (pchan->rotmode == ROT_MODE_QUAT) {
/* quaternions have 720 degree range */
negate_v4(pchan->quat);
-
+
/* tagging */
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
ListBase dsources = {NULL, NULL};
@@ -1981,75 +2275,78 @@ void POSE_OT_quaternions_flip (wmOperatorType *ot)
}
/* ********************************************** */
+/* Clear User Transforms */
-/* context: active channel */
-#if 0
-void pose_special_editmenu(Scene *scene)
-{
- Object *obedit= scene->obedit; // XXX context
- Object *ob= OBACT;
- short nr;
-
- /* paranoia checks */
- if(!ob && !ob->pose) return;
- if(ob==obedit || (ob->mode & OB_MODE_POSE)==0) return;
-
- nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear Paths%x4|Clear User Transform %x5|Relax Pose %x6|%l|AutoName Left-Right%x7|AutoName Front-Back%x8|AutoName Top-Bottom%x9");
- if(nr==1) {
- pose_select_constraint_target(scene);
- }
- else if(nr==2) {
- pose_flip_names();
- }
- else if(nr==3) {
- pose_calculate_path(C, ob);
- }
- else if(nr==4) {
- pose_clear_paths(ob);
- }
- else if(nr==5) {
- pose_clear_user_transforms(ob);
- }
- else if(nr==6) {
- pose_relax();
- }
- else if(ELEM3(nr, 7, 8, 9)) {
- pose_autoside_names(nr-7);
- }
-}
-
-
-/* Restore selected pose-bones to 'action'-defined pose */
-static void pose_clear_user_transforms(Object *ob)
+static int pose_clear_user_transforms_exec (bContext *C, wmOperator *UNUSED(op))
{
- bArmature *arm= ob->data;
- bPoseChannel *pchan;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ float cframe = (float)CFRA;
- if (ob->pose == NULL)
- return;
-
- /* if the object has an action, restore pose to the pose defined by the action by clearing pose on selected bones */
- if (ob->action) {
- /* find selected bones */
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if (pchan->bone && (pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) {
- /* just clear the BONE_UNKEYED flag, allowing this bone to get overwritten by actions again */
- pchan->bone->flag &= ~BONE_UNKEYED;
- }
+ if ((ob->adt) && (ob->adt->action)) {
+ /* XXX: this is just like this to avoid contaminating anything else;
+ * just pose values should change, so this should be fine
+ */
+ bPose *dummyPose = NULL;
+ Object workob = {{0}};
+ bPoseChannel *pchan;
+
+ /* execute animation step for current frame using a dummy copy of the pose */
+ copy_pose(&dummyPose, ob->pose, 0);
+
+ BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
+ workob.type = OB_ARMATURE;
+ workob.data = ob->data;
+ workob.adt = ob->adt;
+ workob.pose = dummyPose;
+
+ BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
+
+ /* copy back values, but on selected bones only */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ pose_bone_do_paste(ob, pchan, 1, 0);
}
- /* clear pose locking flag
- * - this will only clear the user-defined pose in the selected bones, where BONE_UNKEYED has been cleared
- */
- ob->pose->flag |= POSE_DO_UNLOCK;
+ /* free temp data - free manually as was copied without constraints */
+ if (dummyPose) {
+ for (pchan= dummyPose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+ }
+
+ /* was copied without constraints */
+ BLI_freelistN(&dummyPose->chanbase);
+ MEM_freeN(dummyPose);
+ }
}
else {
- /* no action, so restore entire pose to rest pose (cannot restore only selected bones) */
+ /* no animation, so just reset whole pose to rest pose
+ * (cannot just restore for selected though)
+ */
rest_pose(ob->pose);
}
+ /* notifiers and updates */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BIF_undo_push("Clear User Transform");
+ WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_user_transforms_clear (wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear User Transforms";
+ ot->idname= "POSE_OT_user_transforms_clear";
+ ot->description= "Reset pose on selected bones to keyframed state";
+
+ /* callbacks */
+ ot->exec= pose_clear_user_transforms_exec;
+ ot->poll= ED_operator_posemode;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-#endif