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