2.5 - Pose Relax/Push improvements

* 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.
This commit is contained in:
Joshua Leung 2009-09-20 05:05:16 +00:00
parent f4b9ec0e37
commit 22995e9c45
2 changed files with 153 additions and 69 deletions

View 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);

View 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";