synched with trunk at revision 34793
[blender-staging.git] / source / blender / editors / armature / poseSlide.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <stddef.h>
31 #include <string.h>
32 #include <math.h>
33 #include <float.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_math.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_dynstr.h"
40 #include "BLI_dlrbTree.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_armature_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46
47 #include "BKE_fcurve.h"
48
49 #include "BKE_context.h"
50 #include "BKE_report.h"
51
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58
59
60 #include "ED_armature.h"
61 #include "ED_keyframes_draw.h"
62 #include "ED_screen.h"
63
64 #include "armature_intern.h"
65
66 /* **************************************************** */
67 /* == POSE 'SLIDING' TOOLS == 
68  *
69  * A) Push & Relax, Breakdowner
70  * These tools provide the animator with various capabilities
71  * for interactively controlling the spacing of poses, but also
72  * for 'pushing' and/or 'relaxing' extremes as they see fit.
73  *
74  * B) Pose Sculpting
75  * This is yet to be implemented, but the idea here is to use
76  * sculpting techniques to make it easier to pose rigs by allowing
77  * rigs to be manipulated using a familiar paint-based interface. 
78  */
79 /* **************************************************** */
80 /* A) Push & Relax, Breakdowner */
81
82 /* Temporary data shared between these operators */
83 typedef struct tPoseSlideOp {
84         Scene *scene;           /* current scene */
85         ARegion *ar;            /* region that we're operating in (needed for  */
86         Object *ob;                     /* active object that Pose Info comes from */
87         bArmature *arm;         /* armature for pose */
88         
89         ListBase pfLinks;       /* links between posechannels and f-curves  */
90         DLRBT_Tree keys;        /* binary tree for quicker searching for keyframes (when applicable) */
91         
92         int cframe;                     /* current frame number */
93         int prevFrame;          /* frame before current frame (blend-from) */
94         int nextFrame;          /* frame after current frame (blend-to) */
95         
96         int mode;                       /* sliding mode (ePoseSlide_Modes) */
97         int flag;                       // unused for now, but can later get used for storing runtime settings....
98         
99         float percentage;       /* 0-1 value for determining the influence of whatever is relevant */
100 } tPoseSlideOp;
101
102 /* Pose Sliding Modes */
103 typedef enum ePoseSlide_Modes {
104         POSESLIDE_PUSH  = 0,            /* exaggerate the pose... */
105         POSESLIDE_RELAX,                        /* soften the pose... */
106         POSESLIDE_BREAKDOWN,            /* slide between the endpoint poses, finding a 'soft' spot */
107 } ePoseSlide_Modes;
108
109 /* ------------------------------------ */
110
111 /* operator init */
112 static int pose_slide_init (bContext *C, wmOperator *op, short mode)
113 {
114         tPoseSlideOp *pso;
115         bAction *act= NULL;
116         
117         /* init slide-op data */
118         pso= op->customdata= MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
119         
120         /* get info from context */
121         pso->scene= CTX_data_scene(C);
122         pso->ob= CTX_data_active_object(C);
123         pso->arm= (pso->ob)? pso->ob->data : NULL;
124         pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */
125         
126         pso->cframe= pso->scene->r.cfra;
127         pso->mode= mode;
128         
129         /* set range info from property values - these may get overridden for the invoke() */
130         pso->percentage= RNA_float_get(op->ptr, "percentage");
131         pso->prevFrame= RNA_int_get(op->ptr, "prev_frame");
132         pso->nextFrame= RNA_int_get(op->ptr, "next_frame");
133         
134         /* check the settings from the context */
135         if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
136                 return 0;
137         else
138                 act= pso->ob->adt->action;
139         
140         /* for each Pose-Channel which gets affected, get the F-Curves for that channel 
141          * and set the relevant transform flags...
142          */
143         poseAnim_mapping_get(C, &pso->pfLinks, pso->ob, act);
144         
145         /* set depsgraph flags */
146                 /* make sure the lock is set OK, unlock can be accidentally saved? */
147         pso->ob->pose->flag |= POSE_LOCKED;
148         pso->ob->pose->flag &= ~POSE_DO_UNLOCK;
149         
150         /* do basic initialise of RB-BST used for finding keyframes, but leave the filling of it up 
151          * to the caller of this (usually only invoke() will do it, to make things more efficient).
152          */
153         BLI_dlrbTree_init(&pso->keys);
154         
155         /* return status is whether we've got all the data we were requested to get */
156         return 1;
157 }
158
159 /* exiting the operator - free data */
160 static void pose_slide_exit (bContext *C, wmOperator *op)
161 {
162         tPoseSlideOp *pso= op->customdata;
163         
164         /* if data exists, clear its data and exit */
165         if (pso) {
166                 /* free the temp pchan links and their data */
167                 poseAnim_mapping_free(&pso->pfLinks);
168                 
169                 /* free RB-BST for keyframes (if it contained data) */
170                 BLI_dlrbTree_free(&pso->keys);
171                 
172                 /* free data itself */
173                 MEM_freeN(pso);
174         }
175         
176         /* cleanup */
177         op->customdata= NULL;
178 }
179
180 /* ------------------------------------ */
181
182 /* helper for apply() / reset() - refresh the data */
183 static void pose_slide_refresh (bContext *C, tPoseSlideOp *pso)
184 {
185         /* wrapper around the generic version, allowing us to add some custom stuff later still */
186         poseAnim_mapping_refresh(C, pso->scene, pso->ob);
187 }
188
189 /* helper for apply() - perform sliding for some 3-element vector */
190 static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], char *propName)
191 {
192         LinkData *ld=NULL;
193         char *path=NULL;
194         float cframe;
195         
196         /* get the path to use... */
197         path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
198         
199         /* get the current frame number */
200         cframe= (float)pso->cframe;
201         
202         /* using this path, find each matching F-Curve for the variables we're interested in */
203         while ( (ld= poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
204                 FCurve *fcu= (FCurve *)ld->data;
205                 float sVal, eVal;
206                 float w1, w2;
207                 int ch;
208                 
209                 /* get keyframe values for endpoint poses to blend with */
210                         /* previous/start */
211                 sVal= evaluate_fcurve(fcu, (float)pso->prevFrame);
212                         /* next/end */
213                 eVal= evaluate_fcurve(fcu, (float)pso->nextFrame);
214                 
215                 /* get channel index */
216                 ch= fcu->array_index;
217                 
218                 /* calculate the relative weights of the endpoints */
219                 if (pso->mode == POSESLIDE_BREAKDOWN) {
220                         /* get weights from the percentage control */
221                         w1= pso->percentage;    /* this must come second */
222                         w2= 1.0f - w1;                  /* this must come first */
223                 }
224                 else {
225                         /*      - these weights are derived from the relative distance of these 
226                          *        poses from the current frame
227                          *      - they then get normalised so that they only sum up to 1
228                          */
229                         float wtot; 
230                         
231                         w1 = cframe - (float)pso->prevFrame;
232                         w2 = (float)pso->nextFrame - cframe;
233                         
234                         wtot = w1 + w2;
235                         w1 = (w1/wtot);
236                         w2 = (w2/wtot);
237                 }
238                 
239                 /* depending on the mode, calculate the new value
240                  *      - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
241                  *        since multiplication in another order would decrease the value the current frame is closer to
242                  */
243                 switch (pso->mode) {
244                         case POSESLIDE_PUSH: /* make the current pose more pronounced */
245                         {
246                                 /* perform a weighted average here, favouring the middle pose 
247                                  *      - numerator should be larger than denominator to 'expand' the result
248                                  *      - perform this weighting a number of times given by the percentage...
249                                  */
250                                 int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
251                                 
252                                 while (iters-- > 0) {
253                                         vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; 
254                                 }
255                         }
256                                 break;
257                                 
258                         case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
259                         {
260                                 /* perform a weighted average here, favouring the middle pose 
261                                  *      - numerator should be smaller than denominator to 'relax' the result
262                                  *      - perform this weighting a number of times given by the percentage...
263                                  */
264                                 int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
265                                 
266                                 while (iters-- > 0) {
267                                         vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
268                                 }
269                         }
270                                 break;
271                                 
272                         case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
273                         {
274                                 /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
275                                 // TODO: make this use some kind of spline interpolation instead?
276                                 vec[ch]= ((sVal * w2) + (eVal * w1));
277                         }
278                                 break;
279                 }
280                 
281         }
282         
283         /* free the temp path we got */
284         MEM_freeN(path);
285 }
286
287 /* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
288 static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl)
289 {
290         FCurve *fcu_w=NULL, *fcu_x=NULL, *fcu_y=NULL, *fcu_z=NULL;
291         bPoseChannel *pchan= pfl->pchan;
292         LinkData *ld=NULL;
293         char *path=NULL;
294         float cframe;
295         
296         /* get the path to use - this should be quaternion rotations only (needs care) */
297         path= BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
298         
299         /* get the current frame number */
300         cframe= (float)pso->cframe;
301         
302         /* using this path, find each matching F-Curve for the variables we're interested in */
303         while ( (ld= poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
304                 FCurve *fcu= (FCurve *)ld->data;
305                 
306                 /* assign this F-Curve to one of the relevant pointers... */
307                 switch (fcu->array_index) {
308                         case 3: /* z */
309                                 fcu_z= fcu;
310                                 break;
311                         case 2: /* y */
312                                 fcu_y= fcu;
313                                 break;
314                         case 1: /* x */
315                                 fcu_x= fcu;
316                                 break;
317                         case 0: /* w */
318                                 fcu_w= fcu;
319                                 break;
320                 }
321         }
322         
323         /* only if all channels exist, proceed */
324         if (fcu_w && fcu_x && fcu_y && fcu_z) {
325                 float quat_prev[4], quat_next[4];
326                 
327                 /* get 2 quats */
328                 quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame);
329                 quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame);
330                 quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame);
331                 quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame);
332                 
333                 quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame);
334                 quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame);
335                 quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame);
336                 quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame);
337                 
338                 /* perform blending */
339                 if (pso->mode == POSESLIDE_BREAKDOWN) {
340                         /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
341                         interp_qt_qtqt(pchan->quat, quat_prev, quat_next, pso->percentage);
342                 }
343                 else if (pso->mode == POSESLIDE_PUSH) {
344                         float quat_diff[4], quat_orig[4];
345                         
346                         /* calculate the delta transform from the previous to the current */
347                         // TODO: investigate ways to favour one transform more?
348                         sub_qt_qtqt(quat_diff, pchan->quat, quat_prev);
349                         
350                         /* make a copy of the original rotation */
351                         QUATCOPY(quat_orig, pchan->quat);
352                         
353                         /* increase the original by the delta transform, by an amount determined by percentage */
354                         add_qt_qtqt(pchan->quat, quat_orig, quat_diff, pso->percentage);
355                 }
356                 else {
357                         float quat_interp[4], quat_orig[4];
358                         int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
359                         
360                         /* perform this blending several times until a satisfactory result is reached */
361                         while (iters-- > 0) {
362                                 /* calculate the interpolation between the endpoints */
363                                 interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe-pso->prevFrame) / (pso->nextFrame-pso->prevFrame) );
364                                 
365                                 /* make a copy of the original rotation */
366                                 QUATCOPY(quat_orig, pchan->quat);
367                                 
368                                 /* tricky interpolations - blending between original and new */
369                                 interp_qt_qtqt(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
370                         }
371                 }
372         }
373         
374         /* free the path now */
375         MEM_freeN(path);
376 }
377
378 /* apply() - perform the pose sliding based on weighting various poses */
379 static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
380 {
381         tPChanFCurveLink *pfl;
382         
383         /* sanitise the frame ranges */
384         if (pso->prevFrame == pso->nextFrame) {
385                 /* move out one step either side */
386                 pso->prevFrame--;
387                 pso->nextFrame++;
388         }
389         
390         /* for each link, handle each set of transforms */
391         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
392                 /* valid transforms for each PoseChannel should have been noted already 
393                  *      - sliding the pose should be a straightforward exercise for location+rotation, 
394                  *        but rotations get more complicated since we may want to use quaternion blending 
395                  *        for quaternions instead...
396                  */
397                 bPoseChannel *pchan= pfl->pchan;
398                  
399                 if (pchan->flag & POSE_LOC) {
400                         /* calculate these for the 'location' vector, and use location curves */
401                         pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
402                 }
403                 
404                 if (pchan->flag & POSE_SIZE) {
405                         /* calculate these for the 'scale' vector, and use scale curves */
406                         pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
407                 }
408                 
409                 if (pchan->flag & POSE_ROT) {
410                         /* everything depends on the rotation mode */
411                         if (pchan->rotmode > 0) {
412                                 /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
413                                 pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
414                         }
415                         else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
416                                 // TODO: need to figure out how to do this!
417                         }
418                         else {
419                                 /* quaternions - use quaternion blending */
420                                 pose_slide_apply_quat(pso, pfl);
421                         }
422                 }
423         }
424         
425         /* depsgraph updates + redraws */
426         pose_slide_refresh(C, pso);
427 }
428
429 /* perform autokeyframing after changes were made + confirmed */
430 static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso)
431 {
432         /* wrapper around the generic call */
433         poseAnim_mapping_autoKeyframe(C, pso->scene, pso->ob, &pso->pfLinks, (float)pso->cframe);
434 }
435
436 /* reset changes made to current pose */
437 static void pose_slide_reset (bContext *C, tPoseSlideOp *pso)
438 {
439         /* wrapper around the generic call, so that custom stuff can be added later */
440         poseAnim_mapping_reset(&pso->pfLinks);
441 }
442
443 /* ------------------------------------ */
444
445 /* common code for invoke() methods */
446 static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
447 {
448         tPChanFCurveLink *pfl;
449         AnimData *adt= pso->ob->adt;
450         wmWindow *win= CTX_wm_window(C);
451         
452         /* for each link, add all its keyframes to the search tree */
453         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
454                 LinkData *ld;
455                 
456                 /* do this for each F-Curve */
457                 for (ld= pfl->fcurves.first; ld; ld= ld->next) {
458                         FCurve *fcu= (FCurve *)ld->data;
459                         fcurve_to_keylist(adt, fcu, &pso->keys, NULL);
460                 }
461         }
462         
463         /* consolidate these keyframes, and figure out the nearest ones */
464         BLI_dlrbTree_linkedlist_sync(&pso->keys);
465         
466                 /* cancel if no keyframes found... */
467         if (pso->keys.root) {
468                 ActKeyColumn *ak;
469                 float cframe= (float)pso->cframe;
470                 
471                 /* firstly, check if the current frame is a keyframe... */
472                 ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
473                 
474                 if (ak == NULL) {
475                         /* current frame is not a keyframe, so search */
476                         ActKeyColumn *pk= (ActKeyColumn *)BLI_dlrbTree_search_prev(&pso->keys, compare_ak_cfraPtr, &cframe);
477                         ActKeyColumn *nk= (ActKeyColumn *)BLI_dlrbTree_search_next(&pso->keys, compare_ak_cfraPtr, &cframe);
478                         
479                         /* new set the frames */
480                                 /* prev frame */
481                         pso->prevFrame= (pk)? (pk->cfra) : (pso->cframe - 1);
482                         RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
483                                 /* next frame */
484                         pso->nextFrame= (nk)? (nk->cfra) : (pso->cframe + 1);
485                         RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
486                 }
487                 else {
488                         /* current frame itself is a keyframe, so just take keyframes on either side */
489                                 /* prev frame */
490                         pso->prevFrame= (ak->prev)? (ak->prev->cfra) : (pso->cframe - 1);
491                         RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
492                                 /* next frame */
493                         pso->nextFrame= (ak->next)? (ak->next->cfra) : (pso->cframe + 1);
494                         RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
495                 }
496         }
497         else {
498                 BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between.");
499                 return OPERATOR_CANCELLED;
500         }
501         
502         /* initial apply for operator... */
503         // TODO: need to calculate percentage for initial round too...
504         pose_slide_apply(C, op, pso);
505         
506         /* depsgraph updates + redraws */
507         pose_slide_refresh(C, pso);
508         
509         /* set cursor to indicate modal */
510         WM_cursor_modal(win, BC_EW_SCROLLCURSOR);
511         
512         /* add a modal handler for this operator */
513         WM_event_add_modal_handler(C, op);
514         return OPERATOR_RUNNING_MODAL;
515 }
516
517 /* common code for modal() */
518 static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
519 {
520         tPoseSlideOp *pso= op->customdata;
521         wmWindow *win= CTX_wm_window(C);
522         
523         switch (evt->type) {
524                 case LEFTMOUSE: /* confirm */
525                 {
526                         /* return to normal cursor */
527                         WM_cursor_restore(win);
528                         
529                         /* insert keyframes as required... */
530                         pose_slide_autoKeyframe(C, pso);
531                         pose_slide_exit(C, op);
532                         
533                         /* done! */
534                         return OPERATOR_FINISHED;
535                 }
536                 
537                 case ESCKEY:    /* cancel */
538                 case RIGHTMOUSE: 
539                 {
540                         /* return to normal cursor */
541                         WM_cursor_restore(win);
542                         
543                         /* reset transforms back to original state */
544                         pose_slide_reset(C, pso);
545                         
546                         /* depsgraph updates + redraws */
547                         pose_slide_refresh(C, pso);
548                         
549                         /* clean up temp data */
550                         pose_slide_exit(C, op);
551                         
552                         /* cancelled! */
553                         return OPERATOR_CANCELLED;
554                 }
555                         
556                 case MOUSEMOVE: /* calculate new position */
557                 {
558                         /* calculate percentage based on position of mouse (we only use x-axis for now.
559                          * since this is more conveninent for users to do), and store new percentage value 
560                          */
561                         pso->percentage= (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
562                         RNA_float_set(op->ptr, "percentage", pso->percentage);
563                         
564                         /* reset transforms (to avoid accumulation errors) */
565                         pose_slide_reset(C, pso);
566                         
567                         /* apply... */
568                         pose_slide_apply(C, op, pso);
569                 }
570                         break;
571                         
572                 default: /* unhandled event (maybe it was some view manip? */
573                         /* allow to pass through */
574                         return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH;
575         }
576         
577         /* still running... */
578         return OPERATOR_RUNNING_MODAL;
579 }
580
581 /* common code for cancel() */
582 static int pose_slide_cancel (bContext *C, wmOperator *op)
583 {
584         /* cleanup and done */
585         pose_slide_exit(C, op);
586         return OPERATOR_CANCELLED;
587 }
588
589 /* common code for exec() methods */
590 static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
591 {
592         /* settings should have been set up ok for applying, so just apply! */
593         pose_slide_apply(C, op, pso);
594         
595         /* insert keyframes if needed */
596         pose_slide_autoKeyframe(C, pso);
597         
598         /* cleanup and done */
599         pose_slide_exit(C, op);
600         
601         return OPERATOR_FINISHED;
602 }
603
604 /* common code for defining RNA properties */
605 static void pose_slide_opdef_properties (wmOperatorType *ot)
606 {
607         RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame.", 0, 50);
608         RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame.", 0, 50);
609         RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7);
610 }
611
612 /* ------------------------------------ */
613
614 /* invoke() - for 'push' mode */
615 static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt)
616 {
617         tPoseSlideOp *pso;
618         
619         /* initialise data  */
620         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
621                 pose_slide_exit(C, op);
622                 return OPERATOR_CANCELLED;
623         }
624         else
625                 pso= op->customdata;
626         
627         /* do common setup work */
628         return pose_slide_invoke_common(C, op, pso);
629 }
630
631 /* exec() - for push */
632 static int pose_slide_push_exec (bContext *C, wmOperator *op)
633 {
634         tPoseSlideOp *pso;
635         
636         /* initialise data (from RNA-props) */
637         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
638                 pose_slide_exit(C, op);
639                 return OPERATOR_CANCELLED;
640         }
641         else
642                 pso= op->customdata;
643                 
644         /* do common exec work */
645         return pose_slide_exec_common(C, op, pso);
646 }
647
648 void POSE_OT_push (wmOperatorType *ot)
649 {
650         /* identifiers */
651         ot->name= "Push Pose";
652         ot->idname= "POSE_OT_push";
653         ot->description= "Exaggerate the current pose";
654         
655         /* callbacks */
656         ot->exec= pose_slide_push_exec;
657         ot->invoke= pose_slide_push_invoke;
658         ot->modal= pose_slide_modal;
659         ot->cancel= pose_slide_cancel;
660         ot->poll= ED_operator_posemode;
661         
662         /* flags */
663         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
664         
665         /* Properties */
666         pose_slide_opdef_properties(ot);
667 }
668
669 /* ........................ */
670
671 /* invoke() - for 'relax' mode */
672 static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt)
673 {
674         tPoseSlideOp *pso;
675         
676         /* initialise data  */
677         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
678                 pose_slide_exit(C, op);
679                 return OPERATOR_CANCELLED;
680         }
681         else
682                 pso= op->customdata;
683         
684         /* do common setup work */
685         return pose_slide_invoke_common(C, op, pso);
686 }
687
688 /* exec() - for relax */
689 static int pose_slide_relax_exec (bContext *C, wmOperator *op)
690 {
691         tPoseSlideOp *pso;
692         
693         /* initialise data (from RNA-props) */
694         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
695                 pose_slide_exit(C, op);
696                 return OPERATOR_CANCELLED;
697         }
698         else
699                 pso= op->customdata;
700                 
701         /* do common exec work */
702         return pose_slide_exec_common(C, op, pso);
703 }
704
705 void POSE_OT_relax (wmOperatorType *ot)
706 {
707         /* identifiers */
708         ot->name= "Relax Pose";
709         ot->idname= "POSE_OT_relax";
710         ot->description= "Make the current pose more similar to its surrounding ones";
711         
712         /* callbacks */
713         ot->exec= pose_slide_relax_exec;
714         ot->invoke= pose_slide_relax_invoke;
715         ot->modal= pose_slide_modal;
716         ot->cancel= pose_slide_cancel;
717         ot->poll= ED_operator_posemode;
718         
719         /* flags */
720         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
721         
722         /* Properties */
723         pose_slide_opdef_properties(ot);
724 }
725
726 /* ........................ */
727
728 /* invoke() - for 'breakdown' mode */
729 static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt)
730 {
731         tPoseSlideOp *pso;
732         
733         /* initialise data  */
734         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
735                 pose_slide_exit(C, op);
736                 return OPERATOR_CANCELLED;
737         }
738         else
739                 pso= op->customdata;
740         
741         /* do common setup work */
742         return pose_slide_invoke_common(C, op, pso);
743 }
744
745 /* exec() - for breakdown */
746 static int pose_slide_breakdown_exec (bContext *C, wmOperator *op)
747 {
748         tPoseSlideOp *pso;
749         
750         /* initialise data (from RNA-props) */
751         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
752                 pose_slide_exit(C, op);
753                 return OPERATOR_CANCELLED;
754         }
755         else
756                 pso= op->customdata;
757                 
758         /* do common exec work */
759         return pose_slide_exec_common(C, op, pso);
760 }
761
762 void POSE_OT_breakdown (wmOperatorType *ot)
763 {
764         /* identifiers */
765         ot->name= "Pose Breakdowner";
766         ot->idname= "POSE_OT_breakdown";
767         ot->description= "Create a suitable breakdown pose on the current frame";
768         
769         /* callbacks */
770         ot->exec= pose_slide_breakdown_exec;
771         ot->invoke= pose_slide_breakdown_invoke;
772         ot->modal= pose_slide_modal;
773         ot->cancel= pose_slide_cancel;
774         ot->poll= ED_operator_posemode;
775         
776         /* flags */
777         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
778         
779         /* Properties */
780         pose_slide_opdef_properties(ot);
781 }
782
783 /* **************************************************** */