Restoring "Clear User Transforms" operator
authorJoshua Leung <aligorith@gmail.com>
Mon, 15 Aug 2011 13:24:53 +0000 (13:24 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 15 Aug 2011 13:24:53 +0000 (13:24 +0000)
This can now be found as Pose -> Clear Transforms -> Reset Unkeyed, or
via the operator search (known by its old name there)

release/scripts/startup/bl_ui/space_view3d.py
source/blender/editors/armature/armature_intern.h
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/poseobject.c

index c1973bc8555e1cfa7f80881c3cfe12430b0744bf..c38bc0abc96f4c421bbefa54e57d484708d69fa8 100644 (file)
@@ -1262,11 +1262,15 @@ class VIEW3D_MT_pose_transform(bpy.types.Menu):
 
         layout.operator("pose.transforms_clear", text="All")
 
+        layout.separator()
+
         layout.operator("pose.loc_clear", text="Location")
         layout.operator("pose.rot_clear", text="Rotation")
         layout.operator("pose.scale_clear", text="Scale")
 
-        layout.label(text="Origin")
+        layout.separator()
+
+        layout.operator("pose.user_transforms_clear", text="Reset unkeyed")
 
 
 class VIEW3D_MT_pose_slide(bpy.types.Menu):
index cc654f6d2bcb0209bda60cdcfe1f4d6fc6bffd50..47123b7fb4d68cf4a335cfc8e5f3ac42abc5376f 100644 (file)
@@ -93,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);
index 28454fa0fa9ef4da1247896be3185743b88710db..81ece9ddc9a71a969053ccdd600dbf4b5e2025f2 100644 (file)
@@ -108,6 +108,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);
index 961c556b246c99e93d43262b03a3a0c24308ce51..d2f32837d6dabd9bcfc62a66ecd409541895ae59 100644 (file)
@@ -47,6 +47,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"
@@ -1006,6 +1007,130 @@ static void set_pose_keys (Object *ob)
        }
 }
 
+/* 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)
@@ -1048,9 +1173,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");
        
@@ -1074,115 +1199,11 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
        /* 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 */
-                               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);      
-                                       }
-                               }
-                               
-                               /* keyframing tagging */
+                       if (pchan) {
+                               /* keyframing tagging for successful paste */
                                if (autokeyframe_cfra_can_key(scene, &ob->id)) {
                                        ListBase dsources = {NULL, NULL};
                                        
@@ -2187,6 +2208,7 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot)
 }
 
 /* ********************************************** */
+/* Flip Quats */
 
 static int pose_flip_quats_exec (bContext *C, wmOperator *UNUSED(op))
 {
@@ -2251,41 +2273,78 @@ void POSE_OT_quaternions_flip (wmOperatorType *ot)
 }
 
 /* ********************************************** */
+/* Clear User Transforms */
 
-/* context: active channel */
-#if 0
-
-/* 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 *op)
 {
-       bArmature *arm= ob->data;
-       bPoseChannel *pchan;
-       
-       if (ob->pose == NULL)
-               return;
+       Scene *scene = CTX_data_scene(C);
+       Object *ob = CTX_data_active_object(C);
+       float cframe = (float)CFRA;
        
-       /* 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