2.5 - Pose Relax/Push improvements
authorJoshua Leung <aligorith@gmail.com>
Sun, 20 Sep 2009 05:05:16 +0000 (05:05 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sun, 20 Sep 2009 05:05:16 +0000 (05:05 +0000)
* Relax and Push are now interactive. Moving the mouse left<->right decreases/increases (respectively) the number of times the pose is relaxed or pushed. The sensitivity on this could be tweaked as necessary.

* Cancelling these 'pose sliding' tools now correctly restores the initial pose
* Autokeyframing is now only done when the operator is confirmed.

--

Also, made 'View persp/ortho' <-> 'View Persp/Ortho' to be more in line with other operator names, but to also make it easier to read.

source/blender/editors/armature/poseSlide.c
source/blender/editors/space_view3d/view3d_edit.c

index eb290b1f83c2d96b64bee8c4c4f0c63d761bc239..02c23f01f1e88e41bae3b49d8bd2a568ce672b0c 100644 (file)
@@ -135,7 +135,13 @@ typedef struct tPChanFCurveLink {
        
        ListBase fcurves;               /* F-Curves for this PoseChannel */
        bPoseChannel *pchan;    /* Pose Channel which data is attached to */
+       
        char *pchan_path;               /* RNA Path to this Pose Channel (needs to be freed when we're done) */
+       
+       float oldloc[3];                /* transform values at start of operator (to be restored before each modal step) */
+       float oldrot[3];
+       float oldscale[3];
+       float oldquat[4];
 } tPChanFCurveLink;
 
 /* ------------------------------------ */
@@ -202,6 +208,12 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode)
                                pchan->flag |= POSE_ROT;
                        if (transFlags & ACT_TRANS_SCALE)
                                pchan->flag |= POSE_SIZE;
+                               
+                       /* store current transforms */
+                       VECCOPY(pfl->oldloc, pchan->loc);
+                       VECCOPY(pfl->oldrot, pchan->eul);
+                       VECCOPY(pfl->oldscale, pchan->size);
+                       QUATCOPY(pfl->oldquat, pchan->quat);
                }
        }
        CTX_DATA_END;
@@ -261,6 +273,23 @@ static void pose_slide_exit (bContext *C, wmOperator *op)
 
 /* ------------------------------------ */
 
+/* helper for apply() / reset() - refresh the data */
+static void pose_slide_refresh (bContext *C, tPoseSlideOp *pso)
+{
+       /* old optimize trick... this enforces to bypass the depgraph 
+        *      - note: code copied from transform_generics.c -> recalcData()
+        */
+       // FIXME: shouldn't this use the builtin stuff?
+       if ((pso->arm->flag & ARM_DELAYDEFORM)==0)
+               DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA);  /* sets recalc flags */
+       else
+               where_is_pose(pso->scene, pso->ob);
+       
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); 
+}
+
 /* helper for apply() callabcks - find the next F-Curve with matching path... */
 static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path)
 {
@@ -330,22 +359,45 @@ static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, flo
                        w2 = (w2/wtot);
                }
                
-               /* depending on the mode, */
+               /* depending on the mode, calculate the new value
+                *      - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
+                *        since multiplication in another order would decrease the value the current frame is closer to
+                */
                switch (pso->mode) {
                        case POSESLIDE_PUSH: /* make the current pose more pronounced */
-                               // TODO: this is not interactively modifiable!
-                               vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f;
+                       {
+                               /* perform a weighted average here, favouring the middle pose 
+                                *      - numerator should be larger than denominator to 'expand' the result
+                                *      - perform this weighting a number of times given by the percentage...
+                                */
+                               int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
+                               
+                               while (iters-- > 0) {
+                                       vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; 
+                               }
+                       }
                                break;
                                
                        case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
-                               /* apply the value with a hard coded 6th */
-                               // TODO: this is not interactively modifiable!
-                               vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
+                       {
+                               /* perform a weighted average here, favouring the middle pose 
+                                *      - numerator should be smaller than denominator to 'relax' the result
+                                *      - perform this weighting a number of times given by the percentage...
+                                */
+                               int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
+                               
+                               while (iters-- > 0) {
+                                       vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
+                               }
+                       }
                                break;
                                
                        case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
+                       {
                                /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
+                               // TODO: make this use some kind of spline interpolation instead?
                                vec[ch]= ((sVal * w2) + (eVal * w1));
+                       }
                                break;
                }
                
@@ -384,26 +436,6 @@ static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl)
 #endif
 }
 
-/* helper for apply() - perform autokeyframing */
-static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso, bPoseChannel *pchan, KeyingSet *ks)
-{
-       /* insert keyframes as necessary if autokeyframing */
-       if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) {
-               bCommonKeySrc cks;
-               ListBase dsources = {&cks, &cks};
-               
-               /* init common-key-source for use by KeyingSets */
-               memset(&cks, 0, sizeof(bCommonKeySrc));
-               cks.id= &pso->ob->id;
-               
-               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-               cks.pchan= pchan;
-               
-               /* insert keyframes */
-               modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
-       }
-}
-
 /* apply() - perform the pose sliding based on weighting various poses */
 static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
 {
@@ -428,15 +460,11 @@ static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
                if (pchan->flag & POSE_LOC) {
                        /* calculate these for the 'location' vector, and use location curves */
                        pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
-                       /* insert keyframes if needed */
-                       pose_slide_autoKeyframe(C, pso, pchan, pso->ks_loc);
                }
                
                if (pchan->flag & POSE_SIZE) {
                        /* calculate these for the 'scale' vector, and use scale curves */
                        pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
-                       /* insert keyframes if needed */
-                       pose_slide_autoKeyframe(C, pso, pchan, pso->ks_scale);
                }
                
                if (pchan->flag & POSE_ROT) {
@@ -452,24 +480,58 @@ static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
                                /* quaternions - use quaternion blending */
                                pose_slide_apply_quat(pso, pfl);
                        }
-                       
-                       /* insert keyframes if needed */
-                       pose_slide_autoKeyframe(C, pso, pchan, pso->ks_rot);
                }
        }
        
-       /* old optimize trick... this enforces to bypass the depgraph 
-        *      - note: code copied from transform_generics.c -> recalcData()
-        */
-       // FIXME: shouldn't this use the builtin stuff?
-       if ((pso->arm->flag & ARM_DELAYDEFORM)==0)
-               DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA);  /* sets recalc flags */
-       else
-               where_is_pose(pso->scene, pso->ob);
+       /* depsgraph updates + redraws */
+       pose_slide_refresh(C, pso);
+}
+
+/* perform autokeyframing after changes were made + confirmed */
+static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso)
+{
+       /* insert keyframes as necessary if autokeyframing */
+       if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) {
+               bCommonKeySrc cks;
+               ListBase dsources = {&cks, &cks};
+               tPChanFCurveLink *pfl;
+               
+               /* init common-key-source for use by KeyingSets */
+               memset(&cks, 0, sizeof(bCommonKeySrc));
+               cks.id= &pso->ob->id;
+               
+               /* iterate over each pose-channel affected, applying the changes */
+               for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
+                       bPoseChannel *pchan= pfl->pchan;
+                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
+                       cks.pchan= pchan;
+                       
+                       /* insert keyframes */
+                       if (pchan->flag & POSE_LOC)
+                               modify_keyframes(C, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
+                       if (pchan->flag & POSE_ROT)
+                               modify_keyframes(C, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
+                       if (pchan->flag & POSE_SIZE)
+                               modify_keyframes(C, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
+               }
+       }
+}
+
+/* reset changes made to current pose */
+static void pose_slide_reset (bContext *C, tPoseSlideOp *pso)
+{
+       tPChanFCurveLink *pfl;
        
-       /* note, notifier might evolve */
-       WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob);
-       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
+       /* iterate over each pose-channel affected, restoring all channels to their original values */
+       for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
+               bPoseChannel *pchan= pfl->pchan;
+               
+               /* just copy all the values over regardless of whether they changed or not */
+               VECCOPY(pchan->loc, pfl->oldloc);
+               VECCOPY(pchan->eul, pfl->oldrot);
+               VECCOPY(pchan->size, pfl->oldscale);
+               QUATCOPY(pchan->quat, pfl->oldquat);
+       }
 }
 
 /* ------------------------------------ */
@@ -538,24 +600,19 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *
                return OPERATOR_CANCELLED;
        }
        
-       // FIXME: for now, just do modal for breakdowns... 
-       if (pso->mode == POSESLIDE_BREAKDOWN) { 
-               /* initial apply for operator... */
-               pose_slide_apply(C, op, pso);
-               
-               /* set cursor to indicate modal */
-               WM_cursor_modal(win, BC_EW_SCROLLCURSOR);
-               
-               /* add a modal handler for this operator */
-               WM_event_add_modal_handler(C, op);
-               return OPERATOR_RUNNING_MODAL;
-       }
-       else {
-               /* temp static operator code... until a way to include percentage in the formulation comes up */
-               pose_slide_apply(C, op, pso);
-               pose_slide_exit(C, op);
-               return OPERATOR_FINISHED;
-       }
+       /* initial apply for operator... */
+       // TODO: need to calculate percentage for initial round too...
+       pose_slide_apply(C, op, pso);
+       
+       /* depsgraph updates + redraws */
+       pose_slide_refresh(C, pso);
+       
+       /* set cursor to indicate modal */
+       WM_cursor_modal(win, BC_EW_SCROLLCURSOR);
+       
+       /* add a modal handler for this operator */
+       WM_event_add_modal_handler(C, op);
+       return OPERATOR_RUNNING_MODAL;
 }
 
 /* common code for modal() */
@@ -566,15 +623,36 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
        
        switch (evt->type) {
                case LEFTMOUSE: /* confirm */
+               {
+                       /* return to normal cursor */
                        WM_cursor_restore(win);
+                       
+                       /* insert keyframes as required... */
+                       pose_slide_autoKeyframe(C, pso);
                        pose_slide_exit(C, op);
+                       
+                       /* done! */
                        return OPERATOR_FINISHED;
+               }
                
                case ESCKEY:    /* cancel */
                case RIGHTMOUSE: 
+               {
+                       /* return to normal cursor */
                        WM_cursor_restore(win);
+                       
+                       /* reset transforms back to original state */
+                       pose_slide_reset(C, pso);
+                       
+                       /* depsgraph updates + redraws */
+                       pose_slide_refresh(C, pso);
+                       
+                       /* clean up temp data */
                        pose_slide_exit(C, op);
+                       
+                       /* cancelled! */
                        return OPERATOR_CANCELLED;
+               }
                        
                case MOUSEMOVE: /* calculate new position */
                {
@@ -584,6 +662,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);
                        
+                       /* reset transforms (to avoid accumulation errors) */
+                       pose_slide_reset(C, pso);
+                       
                        /* apply... */
                        pose_slide_apply(C, op, pso);
                }
@@ -608,6 +689,9 @@ static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *ps
        /* settings should have been set up ok for applying, so just apply! */
        pose_slide_apply(C, op, pso);
        
+       /* insert keyframes if needed */
+       pose_slide_autoKeyframe(C, pso);
+       
        /* cleanup and done */
        pose_slide_exit(C, op);
        
@@ -668,12 +752,12 @@ void POSE_OT_push (wmOperatorType *ot)
        /* callbacks */
        ot->exec= pose_slide_push_exec;
        ot->invoke= pose_slide_push_invoke;
-       //ot->modal= pose_slide_modal;
-       //ot->cancel= pose_slide_cancel;
+       ot->modal= pose_slide_modal;
+       ot->cancel= pose_slide_cancel;
        ot->poll= ED_operator_posemode;
        
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
        
        /* Properties */
        pose_slide_opdef_properties(ot);
@@ -725,12 +809,12 @@ void POSE_OT_relax (wmOperatorType *ot)
        /* callbacks */
        ot->exec= pose_slide_relax_exec;
        ot->invoke= pose_slide_relax_invoke;
-       //ot->modal= pose_slide_modal;
-       //ot->cancel= pose_slide_cancel;
+       ot->modal= pose_slide_modal;
+       ot->cancel= pose_slide_cancel;
        ot->poll= ED_operator_posemode;
        
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
        
        /* Properties */
        pose_slide_opdef_properties(ot);
index 0faa1f8c16d2caf751dfced2a80199769575f10a..b788dc28311ee944d80744dbf6a4c57766a8dbde 100644 (file)
@@ -1628,7 +1628,7 @@ static int viewpersportho_exec(bContext *C, wmOperator *op)
 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "View persp/ortho";
+       ot->name= "View Persp/Ortho";
        ot->description = "Switch the current view from perspective/orthographic.";
        ot->idname= "VIEW3D_OT_view_persportho";