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