Remove unneeded notifier data added in revision 26219.
[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., 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_math.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         
139         char *pchan_path;               /* RNA Path to this Pose Channel (needs to be freed when we're done) */
140         
141         float oldloc[3];                /* transform values at start of operator (to be restored before each modal step) */
142         float oldrot[3];
143         float oldscale[3];
144         float oldquat[4];
145 } tPChanFCurveLink;
146
147 /* ------------------------------------ */
148
149 /* operator init */
150 static int pose_slide_init (bContext *C, wmOperator *op, short mode)
151 {
152         tPoseSlideOp *pso;
153         bAction *act= NULL;
154         
155         /* init slide-op data */
156         pso= op->customdata= MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
157         
158         /* get info from context */
159         pso->scene= CTX_data_scene(C);
160         pso->ob= CTX_data_active_object(C);
161         pso->arm= (pso->ob)? pso->ob->data : NULL;
162         pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */
163         
164         pso->cframe= pso->scene->r.cfra;
165         pso->mode= mode;
166         
167         /* set range info from property values - these may get overridden for the invoke() */
168         pso->percentage= RNA_float_get(op->ptr, "percentage");
169         pso->prevFrame= RNA_int_get(op->ptr, "prev_frame");
170         pso->nextFrame= RNA_int_get(op->ptr, "next_frame");
171         
172         /* check the settings from the context */
173         if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
174                 return 0;
175         else
176                 act= pso->ob->adt->action;
177         
178         /* for each Pose-Channel which gets affected, get the F-Curves for that channel 
179          * and set the relevant transform flags...
180          */
181         CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
182         {
183                 ListBase curves = {NULL, NULL};
184                 int transFlags = action_get_item_transforms(act, pso->ob, pchan, &curves);
185                 
186                 pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
187                 
188                 /* check if any transforms found... */
189                 if (transFlags) {
190                         /* make new linkage data */
191                         tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
192                         PointerRNA ptr;
193                         
194                         pfl->fcurves= curves;
195                         pfl->pchan= pchan;
196                         
197                         /* get the RNA path to this pchan - this needs to be freed! */
198                         RNA_pointer_create((ID *)pso->ob, &RNA_PoseBone, pchan, &ptr);
199                         pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr);
200                         
201                         /* add linkage data to operator data */
202                         BLI_addtail(&pso->pfLinks, pfl);
203                         
204                         /* set pchan's transform flags */
205                         if (transFlags & ACT_TRANS_LOC)
206                                 pchan->flag |= POSE_LOC;
207                         if (transFlags & ACT_TRANS_ROT)
208                                 pchan->flag |= POSE_ROT;
209                         if (transFlags & ACT_TRANS_SCALE)
210                                 pchan->flag |= POSE_SIZE;
211                                 
212                         /* store current transforms */
213                         VECCOPY(pfl->oldloc, pchan->loc);
214                         VECCOPY(pfl->oldrot, pchan->eul);
215                         VECCOPY(pfl->oldscale, pchan->size);
216                         QUATCOPY(pfl->oldquat, pchan->quat);
217                 }
218         }
219         CTX_DATA_END;
220         
221         /* set depsgraph flags */
222                 /* make sure the lock is set OK, unlock can be accidentally saved? */
223         pso->ob->pose->flag |= POSE_LOCKED;
224         pso->ob->pose->flag &= ~POSE_DO_UNLOCK;
225         
226         /* do basic initialise of RB-BST used for finding keyframes, but leave the filling of it up 
227          * to the caller of this (usually only invoke() will do it, to make things more efficient).
228          */
229         BLI_dlrbTree_init(&pso->keys);
230         
231         /* get builtin KeyingSets */
232         pso->ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location");
233         pso->ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
234         pso->ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scaling");
235         
236         /* return status is whether we've got all the data we were requested to get */
237         return 1;
238 }
239
240 /* exiting the operator - free data */
241 static void pose_slide_exit (bContext *C, wmOperator *op)
242 {
243         tPoseSlideOp *pso= op->customdata;
244         
245         /* if data exists, clear its data and exit */
246         if (pso) {
247                 tPChanFCurveLink *pfl, *pfln=NULL;
248                 
249                 /* free the temp pchan links and their data */
250                 for (pfl= pso->pfLinks.first; pfl; pfl= pfln) {
251                         pfln= pfl->next;
252                         
253                         /* free list of F-Curve reference links */
254                         BLI_freelistN(&pfl->fcurves);
255                         
256                         /* free pchan RNA Path */
257                         MEM_freeN(pfl->pchan_path);
258                         
259                         /* free link itself */
260                         BLI_freelinkN(&pso->pfLinks, pfl);
261                 }
262                 
263                 /* free RB-BST for keyframes (if it contained data) */
264                 BLI_dlrbTree_free(&pso->keys);
265                 
266                 /* free data itself */
267                 MEM_freeN(pso);
268         }
269         
270         /* cleanup */
271         op->customdata= NULL;
272 }
273
274 /* ------------------------------------ */
275
276 /* helper for apply() / reset() - refresh the data */
277 static void pose_slide_refresh (bContext *C, tPoseSlideOp *pso)
278 {
279         /* old optimize trick... this enforces to bypass the depgraph 
280          *      - note: code copied from transform_generics.c -> recalcData()
281          */
282         // FIXME: shouldn't this use the builtin stuff?
283         if ((pso->arm->flag & ARM_DELAYDEFORM)==0)
284                 DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA);  /* sets recalc flags */
285         else
286                 where_is_pose(pso->scene, pso->ob);
287         
288         /* note, notifier might evolve */
289         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob);
290 }
291
292 /* helper for apply() callabcks - find the next F-Curve with matching path... */
293 static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path)
294 {
295         LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL;
296         LinkData *ld;
297         
298         /* check each link to see if the linked F-Curve has a matching path */
299         for (ld= first; ld; ld= ld->next) {
300                 FCurve *fcu= (FCurve *)ld->data;
301                 
302                 /* check if paths match */
303                 if (strcmp(path, fcu->rna_path) == 0)
304                         return ld;
305         }       
306         
307         /* none found */
308         return NULL;
309 }
310
311 /* helper for apply() - perform sliding for some 3-element vector */
312 static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], char *propName)
313 {
314         LinkData *ld=NULL;
315         char *path=NULL;
316         float cframe;
317         
318         /* get the path to use... */
319         path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
320         
321         /* get the current frame number */
322         cframe= (float)pso->cframe;
323         
324         /* using this path, find each matching F-Curve for the variables we're interested in */
325         while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) {
326                 FCurve *fcu= (FCurve *)ld->data;
327                 float sVal, eVal;
328                 float w1, w2;
329                 int ch;
330                 
331                 /* get keyframe values for endpoint poses to blend with */
332                         /* previous/start */
333                 sVal= evaluate_fcurve(fcu, (float)pso->prevFrame);
334                         /* next/end */
335                 eVal= evaluate_fcurve(fcu, (float)pso->nextFrame);
336                 
337                 /* get channel index */
338                 ch= fcu->array_index;
339                 
340                 /* calculate the relative weights of the endpoints */
341                 if (pso->mode == POSESLIDE_BREAKDOWN) {
342                         /* get weights from the percentage control */
343                         w1= pso->percentage;    /* this must come second */
344                         w2= 1.0f - w1;                  /* this must come first */
345                 }
346                 else {
347                         /*      - these weights are derived from the relative distance of these 
348                          *        poses from the current frame
349                          *      - they then get normalised so that they only sum up to 1
350                          */
351                         float wtot; 
352                         
353                         w1 = cframe - (float)pso->prevFrame;
354                         w2 = (float)pso->nextFrame - cframe;
355                         
356                         wtot = w1 + w2;
357                         w1 = (w1/wtot);
358                         w2 = (w2/wtot);
359                 }
360                 
361                 /* depending on the mode, calculate the new value
362                  *      - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
363                  *        since multiplication in another order would decrease the value the current frame is closer to
364                  */
365                 switch (pso->mode) {
366                         case POSESLIDE_PUSH: /* make the current pose more pronounced */
367                         {
368                                 /* perform a weighted average here, favouring the middle pose 
369                                  *      - numerator should be larger than denominator to 'expand' the result
370                                  *      - perform this weighting a number of times given by the percentage...
371                                  */
372                                 int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
373                                 
374                                 while (iters-- > 0) {
375                                         vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; 
376                                 }
377                         }
378                                 break;
379                                 
380                         case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
381                         {
382                                 /* perform a weighted average here, favouring the middle pose 
383                                  *      - numerator should be smaller than denominator to 'relax' the result
384                                  *      - perform this weighting a number of times given by the percentage...
385                                  */
386                                 int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
387                                 
388                                 while (iters-- > 0) {
389                                         vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
390                                 }
391                         }
392                                 break;
393                                 
394                         case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
395                         {
396                                 /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
397                                 // TODO: make this use some kind of spline interpolation instead?
398                                 vec[ch]= ((sVal * w2) + (eVal * w1));
399                         }
400                                 break;
401                 }
402                 
403         }
404         
405         /* free the temp path we got */
406         MEM_freeN(path);
407 }
408
409 /* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
410 static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl)
411 {
412         FCurve *fcu_w=NULL, *fcu_x=NULL, *fcu_y=NULL, *fcu_z=NULL;
413         bPoseChannel *pchan= pfl->pchan;
414         LinkData *ld=NULL;
415         char *path=NULL;
416         float cframe;
417         
418         /* get the path to use - this should be quaternion rotations only (needs care) */
419         path= BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
420         
421         /* get the current frame number */
422         cframe= (float)pso->cframe;
423         
424         /* using this path, find each matching F-Curve for the variables we're interested in */
425         while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) {
426                 FCurve *fcu= (FCurve *)ld->data;
427                 
428                 /* assign this F-Curve to one of the relevant pointers... */
429                 switch (fcu->array_index) {
430                         case 3: /* z */
431                                 fcu_z= fcu;
432                                 break;
433                         case 2: /* y */
434                                 fcu_y= fcu;
435                                 break;
436                         case 1: /* x */
437                                 fcu_x= fcu;
438                                 break;
439                         case 0: /* w */
440                                 fcu_w= fcu;
441                                 break;
442                 }
443         }
444         
445         /* only if all channels exist, proceed */
446         if (fcu_w && fcu_x && fcu_y && fcu_z) {
447                 float quat_prev[4], quat_next[4];
448                 
449                 /* get 2 quats */
450                 quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame);
451                 quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame);
452                 quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame);
453                 quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame);
454                 
455                 quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame);
456                 quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame);
457                 quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame);
458                 quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame);
459                 
460                 /* perform blending */
461                 if (pso->mode == POSESLIDE_BREAKDOWN) {
462                         /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
463                         interp_qt_qtqt(pchan->quat, quat_prev, quat_next, pso->percentage);
464                 }
465                 else if (pso->mode == POSESLIDE_PUSH) {
466                         float quat_diff[4], quat_orig[4];
467                         
468                         /* calculate the delta transform from the previous to the current */
469                         // TODO: investigate ways to favour one transform more?
470                         sub_qt_qtqt(quat_diff, pchan->quat, quat_prev);
471                         
472                         /* make a copy of the original rotation */
473                         QUATCOPY(quat_orig, pchan->quat);
474                         
475                         /* increase the original by the delta transform, by an amount determined by percentage */
476                         add_qt_qtqt(pchan->quat, quat_orig, quat_diff, pso->percentage);
477                 }
478                 else {
479                         float quat_interp[4], quat_orig[4];
480                         int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
481                         
482                         /* perform this blending several times until a satisfactory result is reached */
483                         while (iters-- > 0) {
484                                 /* calculate the interpolation between the endpoints */
485                                 interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe-pso->prevFrame) / (pso->nextFrame-pso->prevFrame) );
486                                 
487                                 /* make a copy of the original rotation */
488                                 QUATCOPY(quat_orig, pchan->quat);
489                                 
490                                 /* tricky interpolations - blending between original and new */
491                                 interp_qt_qtqt(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
492                         }
493                 }
494         }
495         
496         /* free the path now */
497         MEM_freeN(path);
498 }
499
500 /* apply() - perform the pose sliding based on weighting various poses */
501 static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
502 {
503         tPChanFCurveLink *pfl;
504         
505         /* sanitise the frame ranges */
506         if (pso->prevFrame == pso->nextFrame) {
507                 /* move out one step either side */
508                 pso->prevFrame--;
509                 pso->nextFrame++;
510         }
511         
512         /* for each link, handle each set of transforms */
513         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
514                 /* valid transforms for each PoseChannel should have been noted already 
515                  *      - sliding the pose should be a straightforward exercise for location+rotation, 
516                  *        but rotations get more complicated since we may want to use quaternion blending 
517                  *        for quaternions instead...
518                  */
519                 bPoseChannel *pchan= pfl->pchan;
520                  
521                 if (pchan->flag & POSE_LOC) {
522                         /* calculate these for the 'location' vector, and use location curves */
523                         pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
524                 }
525                 
526                 if (pchan->flag & POSE_SIZE) {
527                         /* calculate these for the 'scale' vector, and use scale curves */
528                         pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
529                 }
530                 
531                 if (pchan->flag & POSE_ROT) {
532                         /* everything depends on the rotation mode */
533                         if (pchan->rotmode > 0) {
534                                 /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
535                                 pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
536                         }
537                         else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
538                                 // TODO: need to figure out how to do this!
539                         }
540                         else {
541                                 /* quaternions - use quaternion blending */
542                                 pose_slide_apply_quat(pso, pfl);
543                         }
544                 }
545         }
546         
547         /* depsgraph updates + redraws */
548         pose_slide_refresh(C, pso);
549 }
550
551 /* perform autokeyframing after changes were made + confirmed */
552 static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso)
553 {
554         /* insert keyframes as necessary if autokeyframing */
555         if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) {
556                 bCommonKeySrc cks;
557                 ListBase dsources = {&cks, &cks};
558                 tPChanFCurveLink *pfl;
559                 
560                 /* init common-key-source for use by KeyingSets */
561                 memset(&cks, 0, sizeof(bCommonKeySrc));
562                 cks.id= &pso->ob->id;
563                 
564                 /* iterate over each pose-channel affected, applying the changes */
565                 for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
566                         bPoseChannel *pchan= pfl->pchan;
567                         /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
568                         cks.pchan= pchan;
569                         
570                         /* insert keyframes */
571                         if (pchan->flag & POSE_LOC)
572                                 modify_keyframes(pso->scene, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
573                         if (pchan->flag & POSE_ROT)
574                                 modify_keyframes(pso->scene, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
575                         if (pchan->flag & POSE_SIZE)
576                                 modify_keyframes(pso->scene, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
577                 }
578         }
579 }
580
581 /* reset changes made to current pose */
582 static void pose_slide_reset (bContext *C, tPoseSlideOp *pso)
583 {
584         tPChanFCurveLink *pfl;
585         
586         /* iterate over each pose-channel affected, restoring all channels to their original values */
587         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
588                 bPoseChannel *pchan= pfl->pchan;
589                 
590                 /* just copy all the values over regardless of whether they changed or not */
591                 VECCOPY(pchan->loc, pfl->oldloc);
592                 VECCOPY(pchan->eul, pfl->oldrot);
593                 VECCOPY(pchan->size, pfl->oldscale);
594                 QUATCOPY(pchan->quat, pfl->oldquat);
595         }
596 }
597
598 /* ------------------------------------ */
599
600 /* common code for invoke() methods */
601 static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
602 {
603         tPChanFCurveLink *pfl;
604         AnimData *adt= pso->ob->adt;
605         wmWindow *win= CTX_wm_window(C);
606         
607         /* for each link, add all its keyframes to the search tree */
608         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
609                 LinkData *ld;
610                 
611                 /* do this for each F-Curve */
612                 for (ld= pfl->fcurves.first; ld; ld= ld->next) {
613                         FCurve *fcu= (FCurve *)ld->data;
614                         fcurve_to_keylist(adt, fcu, &pso->keys, NULL);
615                 }
616         }
617         
618         /* consolidate these keyframes, and figure out the nearest ones */
619         BLI_dlrbTree_linkedlist_sync(&pso->keys);
620         
621                 /* cancel if no keyframes found... */
622         if (pso->keys.root) {
623                 ActKeyColumn *ak;
624                 float cframe= (float)pso->cframe;
625                 
626                 /* firstly, check if the current frame is a keyframe... */
627                 ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
628                 
629                 if (ak == NULL) {
630                         /* current frame is not a keyframe, so search */
631                         ActKeyColumn *pk= (ActKeyColumn *)BLI_dlrbTree_search_prev(&pso->keys, compare_ak_cfraPtr, &cframe);
632                         ActKeyColumn *nk= (ActKeyColumn *)BLI_dlrbTree_search_next(&pso->keys, compare_ak_cfraPtr, &cframe);
633                         
634                         /* new set the frames */
635                                 /* prev frame */
636                         pso->prevFrame= (pk)? (pk->cfra) : (pso->cframe - 1);
637                         RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
638                                 /* next frame */
639                         pso->nextFrame= (nk)? (nk->cfra) : (pso->cframe + 1);
640                         RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
641                 }
642                 else {
643                         /* current frame itself is a keyframe, so just take keyframes on either side */
644                                 /* prev frame */
645                         pso->prevFrame= (ak->prev)? (ak->prev->cfra) : (pso->cframe - 1);
646                         RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
647                                 /* next frame */
648                         pso->nextFrame= (ak->next)? (ak->next->cfra) : (pso->cframe + 1);
649                         RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
650                 }
651         }
652         else {
653                 BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between.");
654                 return OPERATOR_CANCELLED;
655         }
656         
657         /* initial apply for operator... */
658         // TODO: need to calculate percentage for initial round too...
659         pose_slide_apply(C, op, pso);
660         
661         /* depsgraph updates + redraws */
662         pose_slide_refresh(C, pso);
663         
664         /* set cursor to indicate modal */
665         WM_cursor_modal(win, BC_EW_SCROLLCURSOR);
666         
667         /* add a modal handler for this operator */
668         WM_event_add_modal_handler(C, op);
669         return OPERATOR_RUNNING_MODAL;
670 }
671
672 /* common code for modal() */
673 static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
674 {
675         tPoseSlideOp *pso= op->customdata;
676         wmWindow *win= CTX_wm_window(C);
677         
678         switch (evt->type) {
679                 case LEFTMOUSE: /* confirm */
680                 {
681                         /* return to normal cursor */
682                         WM_cursor_restore(win);
683                         
684                         /* insert keyframes as required... */
685                         pose_slide_autoKeyframe(C, pso);
686                         pose_slide_exit(C, op);
687                         
688                         /* done! */
689                         return OPERATOR_FINISHED;
690                 }
691                 
692                 case ESCKEY:    /* cancel */
693                 case RIGHTMOUSE: 
694                 {
695                         /* return to normal cursor */
696                         WM_cursor_restore(win);
697                         
698                         /* reset transforms back to original state */
699                         pose_slide_reset(C, pso);
700                         
701                         /* depsgraph updates + redraws */
702                         pose_slide_refresh(C, pso);
703                         
704                         /* clean up temp data */
705                         pose_slide_exit(C, op);
706                         
707                         /* cancelled! */
708                         return OPERATOR_CANCELLED;
709                 }
710                         
711                 case MOUSEMOVE: /* calculate new position */
712                 {
713                         /* calculate percentage based on position of mouse (we only use x-axis for now.
714                          * since this is more conveninent for users to do), and store new percentage value 
715                          */
716                         pso->percentage= (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
717                         RNA_float_set(op->ptr, "percentage", pso->percentage);
718                         
719                         /* reset transforms (to avoid accumulation errors) */
720                         pose_slide_reset(C, pso);
721                         
722                         /* apply... */
723                         pose_slide_apply(C, op, pso);
724                 }
725                         break;
726                         
727                 default: /* unhandled event (maybe it was some view manip? */
728                         /* allow to pass through */
729                         return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH;
730         }
731         
732         /* still running... */
733         return OPERATOR_RUNNING_MODAL;
734 }
735
736 /* common code for cancel() */
737 static int pose_slide_cancel (bContext *C, wmOperator *op)
738 {
739         /* cleanup and done */
740         pose_slide_exit(C, op);
741         return OPERATOR_CANCELLED;
742 }
743
744 /* common code for exec() methods */
745 static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
746 {
747         /* settings should have been set up ok for applying, so just apply! */
748         pose_slide_apply(C, op, pso);
749         
750         /* insert keyframes if needed */
751         pose_slide_autoKeyframe(C, pso);
752         
753         /* cleanup and done */
754         pose_slide_exit(C, op);
755         
756         return OPERATOR_FINISHED;
757 }
758
759 /* common code for defining RNA properties */
760 static void pose_slide_opdef_properties (wmOperatorType *ot)
761 {
762         RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame.", 0, 50);
763         RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame.", 0, 50);
764         RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7);
765 }
766
767 /* ------------------------------------ */
768
769 /* invoke() - for 'push' mode */
770 static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt)
771 {
772         tPoseSlideOp *pso;
773         
774         /* initialise data  */
775         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
776                 pose_slide_exit(C, op);
777                 return OPERATOR_CANCELLED;
778         }
779         else
780                 pso= op->customdata;
781         
782         /* do common setup work */
783         return pose_slide_invoke_common(C, op, pso);
784 }
785
786 /* exec() - for push */
787 static int pose_slide_push_exec (bContext *C, wmOperator *op)
788 {
789         tPoseSlideOp *pso;
790         
791         /* initialise data (from RNA-props) */
792         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
793                 pose_slide_exit(C, op);
794                 return OPERATOR_CANCELLED;
795         }
796         else
797                 pso= op->customdata;
798                 
799         /* do common exec work */
800         return pose_slide_exec_common(C, op, pso);
801 }
802
803 void POSE_OT_push (wmOperatorType *ot)
804 {
805         /* identifiers */
806         ot->name= "Push Pose";
807         ot->idname= "POSE_OT_push";
808         ot->description= "Exaggerate the current pose";
809         
810         /* callbacks */
811         ot->exec= pose_slide_push_exec;
812         ot->invoke= pose_slide_push_invoke;
813         ot->modal= pose_slide_modal;
814         ot->cancel= pose_slide_cancel;
815         ot->poll= ED_operator_posemode;
816         
817         /* flags */
818         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
819         
820         /* Properties */
821         pose_slide_opdef_properties(ot);
822 }
823
824 /* ........................ */
825
826 /* invoke() - for 'relax' mode */
827 static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt)
828 {
829         tPoseSlideOp *pso;
830         
831         /* initialise data  */
832         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
833                 pose_slide_exit(C, op);
834                 return OPERATOR_CANCELLED;
835         }
836         else
837                 pso= op->customdata;
838         
839         /* do common setup work */
840         return pose_slide_invoke_common(C, op, pso);
841 }
842
843 /* exec() - for relax */
844 static int pose_slide_relax_exec (bContext *C, wmOperator *op)
845 {
846         tPoseSlideOp *pso;
847         
848         /* initialise data (from RNA-props) */
849         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
850                 pose_slide_exit(C, op);
851                 return OPERATOR_CANCELLED;
852         }
853         else
854                 pso= op->customdata;
855                 
856         /* do common exec work */
857         return pose_slide_exec_common(C, op, pso);
858 }
859
860 void POSE_OT_relax (wmOperatorType *ot)
861 {
862         /* identifiers */
863         ot->name= "Relax Pose";
864         ot->idname= "POSE_OT_relax";
865         ot->description= "Make the current pose more similar to its surrounding ones.";
866         
867         /* callbacks */
868         ot->exec= pose_slide_relax_exec;
869         ot->invoke= pose_slide_relax_invoke;
870         ot->modal= pose_slide_modal;
871         ot->cancel= pose_slide_cancel;
872         ot->poll= ED_operator_posemode;
873         
874         /* flags */
875         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
876         
877         /* Properties */
878         pose_slide_opdef_properties(ot);
879 }
880
881 /* ........................ */
882
883 /* invoke() - for 'breakdown' mode */
884 static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt)
885 {
886         tPoseSlideOp *pso;
887         
888         /* initialise data  */
889         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
890                 pose_slide_exit(C, op);
891                 return OPERATOR_CANCELLED;
892         }
893         else
894                 pso= op->customdata;
895         
896         /* do common setup work */
897         return pose_slide_invoke_common(C, op, pso);
898 }
899
900 /* exec() - for breakdown */
901 static int pose_slide_breakdown_exec (bContext *C, wmOperator *op)
902 {
903         tPoseSlideOp *pso;
904         
905         /* initialise data (from RNA-props) */
906         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
907                 pose_slide_exit(C, op);
908                 return OPERATOR_CANCELLED;
909         }
910         else
911                 pso= op->customdata;
912                 
913         /* do common exec work */
914         return pose_slide_exec_common(C, op, pso);
915 }
916
917 void POSE_OT_breakdown (wmOperatorType *ot)
918 {
919         /* identifiers */
920         ot->name= "Pose Breakdowner";
921         ot->idname= "POSE_OT_breakdown";
922         ot->description= "Create a suitable breakdown pose on the current frame.";
923         
924         /* callbacks */
925         ot->exec= pose_slide_breakdown_exec;
926         ot->invoke= pose_slide_breakdown_invoke;
927         ot->modal= pose_slide_modal;
928         ot->cancel= pose_slide_cancel;
929         ot->poll= ED_operator_posemode;
930         
931         /* flags */
932         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
933         
934         /* Properties */
935         pose_slide_opdef_properties(ot);
936 }
937
938 /* **************************************************** */