Manual merge of soc-2009-kazanbas branch:
[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         
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_pchans) 
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_PoseChannel, 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         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); 
291 }
292
293 /* helper for apply() callabcks - find the next F-Curve with matching path... */
294 static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path)
295 {
296         LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL;
297         LinkData *ld;
298         
299         /* check each link to see if the linked F-Curve has a matching path */
300         for (ld= first; ld; ld= ld->next) {
301                 FCurve *fcu= (FCurve *)ld->data;
302                 
303                 /* check if paths match */
304                 if (strcmp(path, fcu->rna_path) == 0)
305                         return ld;
306         }       
307         
308         /* none found */
309         return NULL;
310 }
311
312 /* helper for apply() - perform sliding for some 3-element vector */
313 static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], char *propName)
314 {
315         LinkData *ld=NULL;
316         char *path=NULL;
317         float cframe;
318         
319         /* get the path to use... */
320         path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
321         
322         /* get the current frame number */
323         cframe= (float)pso->cframe;
324         
325         /* using this path, find each matching F-Curve for the variables we're interested in */
326         while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) {
327                 FCurve *fcu= (FCurve *)ld->data;
328                 float sVal, eVal;
329                 float w1, w2;
330                 int ch;
331                 
332                 /* get keyframe values for endpoint poses to blend with */
333                         /* previous/start */
334                 sVal= evaluate_fcurve(fcu, (float)pso->prevFrame);
335                         /* next/end */
336                 eVal= evaluate_fcurve(fcu, (float)pso->nextFrame);
337                 
338                 /* get channel index */
339                 ch= fcu->array_index;
340                 
341                 /* calculate the relative weights of the endpoints */
342                 if (pso->mode == POSESLIDE_BREAKDOWN) {
343                         /* get weights from the percentage control */
344                         w1= pso->percentage;    /* this must come second */
345                         w2= 1.0f - w1;                  /* this must come first */
346                 }
347                 else {
348                         /*      - these weights are derived from the relative distance of these 
349                          *        poses from the current frame
350                          *      - they then get normalised so that they only sum up to 1
351                          */
352                         float wtot; 
353                         
354                         w1 = cframe - (float)pso->prevFrame;
355                         w2 = (float)pso->nextFrame - cframe;
356                         
357                         wtot = w1 + w2;
358                         w1 = (w1/wtot);
359                         w2 = (w2/wtot);
360                 }
361                 
362                 /* depending on the mode, calculate the new value
363                  *      - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
364                  *        since multiplication in another order would decrease the value the current frame is closer to
365                  */
366                 switch (pso->mode) {
367                         case POSESLIDE_PUSH: /* make the current pose more pronounced */
368                         {
369                                 /* perform a weighted average here, favouring the middle pose 
370                                  *      - numerator should be larger than denominator to 'expand' the result
371                                  *      - perform this weighting a number of times given by the percentage...
372                                  */
373                                 int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
374                                 
375                                 while (iters-- > 0) {
376                                         vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; 
377                                 }
378                         }
379                                 break;
380                                 
381                         case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
382                         {
383                                 /* perform a weighted average here, favouring the middle pose 
384                                  *      - numerator should be smaller than denominator to 'relax' the result
385                                  *      - perform this weighting a number of times given by the percentage...
386                                  */
387                                 int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
388                                 
389                                 while (iters-- > 0) {
390                                         vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
391                                 }
392                         }
393                                 break;
394                                 
395                         case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
396                         {
397                                 /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
398                                 // TODO: make this use some kind of spline interpolation instead?
399                                 vec[ch]= ((sVal * w2) + (eVal * w1));
400                         }
401                                 break;
402                 }
403                 
404         }
405         
406         /* free the temp path we got */
407         MEM_freeN(path);
408 }
409
410 /* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
411 static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl)
412 {
413         FCurve *fcu_w=NULL, *fcu_x=NULL, *fcu_y=NULL, *fcu_z=NULL;
414         bPoseChannel *pchan= pfl->pchan;
415         LinkData *ld=NULL;
416         char *path=NULL;
417         float cframe;
418         
419         /* get the path to use - this should be quaternion rotations only (needs care) */
420         path= BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation");
421         
422         /* get the current frame number */
423         cframe= (float)pso->cframe;
424         
425         /* using this path, find each matching F-Curve for the variables we're interested in */
426         while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) {
427                 FCurve *fcu= (FCurve *)ld->data;
428                 
429                 /* assign this F-Curve to one of the relevant pointers... */
430                 switch (fcu->array_index) {
431                         case 3: /* z */
432                                 fcu_z= fcu;
433                                 break;
434                         case 2: /* y */
435                                 fcu_y= fcu;
436                                 break;
437                         case 1: /* x */
438                                 fcu_x= fcu;
439                                 break;
440                         case 0: /* w */
441                                 fcu_w= fcu;
442                                 break;
443                 }
444         }
445         
446         /* only if all channels exist, proceed */
447         if (fcu_w && fcu_x && fcu_y && fcu_z) {
448                 float quat_prev[4], quat_next[4];
449                 
450                 /* get 2 quats */
451                 quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame);
452                 quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame);
453                 quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame);
454                 quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame);
455                 
456                 quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame);
457                 quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame);
458                 quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame);
459                 quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame);
460                 
461                 /* perform blending */
462                 if (pso->mode == POSESLIDE_BREAKDOWN) {
463                         /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
464                         QuatInterpol(pchan->quat, quat_prev, quat_next, pso->percentage);
465                 }
466                 else {
467                         float quat_interp[4], quat_orig[4];
468                         int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
469                         
470                         /* perform this blending several times until a satisfactory result is reached */
471                         while (iters-- > 0) {
472                                 /* calculate the interpolation between the endpoints */
473                                 QuatInterpol(quat_interp, quat_prev, quat_next, (cframe-pso->prevFrame) / (pso->nextFrame-pso->prevFrame) );
474                                 
475                                 /* make a copy of the original rotation */
476                                 QUATCOPY(quat_orig, pchan->quat);
477                                 
478                                 /* tricky interpolations - mode-dependent blending between original and new */
479                                 if (pso->mode == POSESLIDE_RELAX) // xxx this was the original code, so should work fine
480                                         QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
481                                 else // I'm just guessing here...
482                                         QuatInterpol(pchan->quat, quat_orig, quat_interp, 6.0f/5.0f);
483                         }
484                 }
485         }
486         
487         /* free the path now */
488         MEM_freeN(path);
489 }
490
491 /* apply() - perform the pose sliding based on weighting various poses */
492 static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
493 {
494         tPChanFCurveLink *pfl;
495         
496         /* sanitise the frame ranges */
497         if (pso->prevFrame == pso->nextFrame) {
498                 /* move out one step either side */
499                 pso->prevFrame--;
500                 pso->nextFrame++;
501         }
502         
503         /* for each link, handle each set of transforms */
504         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
505                 /* valid transforms for each PoseChannel should have been noted already 
506                  *      - sliding the pose should be a straightforward exercise for location+rotation, 
507                  *        but rotations get more complicated since we may want to use quaternion blending 
508                  *        for quaternions instead...
509                  */
510                 bPoseChannel *pchan= pfl->pchan;
511                  
512                 if (pchan->flag & POSE_LOC) {
513                         /* calculate these for the 'location' vector, and use location curves */
514                         pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
515                 }
516                 
517                 if (pchan->flag & POSE_SIZE) {
518                         /* calculate these for the 'scale' vector, and use scale curves */
519                         pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
520                 }
521                 
522                 if (pchan->flag & POSE_ROT) {
523                         /* everything depends on the rotation mode */
524                         if (pchan->rotmode > 0) {
525                                 /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
526                                 pose_slide_apply_vec3(pso, pfl, pchan->eul, "euler_rotation");
527                         }
528                         else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
529                                 // TODO: need to figure out how to do this!
530                         }
531                         else {
532                                 /* quaternions - use quaternion blending */
533                                 pose_slide_apply_quat(pso, pfl);
534                         }
535                 }
536         }
537         
538         /* depsgraph updates + redraws */
539         pose_slide_refresh(C, pso);
540 }
541
542 /* perform autokeyframing after changes were made + confirmed */
543 static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso)
544 {
545         /* insert keyframes as necessary if autokeyframing */
546         if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) {
547                 bCommonKeySrc cks;
548                 ListBase dsources = {&cks, &cks};
549                 tPChanFCurveLink *pfl;
550                 
551                 /* init common-key-source for use by KeyingSets */
552                 memset(&cks, 0, sizeof(bCommonKeySrc));
553                 cks.id= &pso->ob->id;
554                 
555                 /* iterate over each pose-channel affected, applying the changes */
556                 for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
557                         bPoseChannel *pchan= pfl->pchan;
558                         /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
559                         cks.pchan= pchan;
560                         
561                         /* insert keyframes */
562                         if (pchan->flag & POSE_LOC)
563                                 modify_keyframes(C, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
564                         if (pchan->flag & POSE_ROT)
565                                 modify_keyframes(C, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
566                         if (pchan->flag & POSE_SIZE)
567                                 modify_keyframes(C, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
568                 }
569         }
570 }
571
572 /* reset changes made to current pose */
573 static void pose_slide_reset (bContext *C, tPoseSlideOp *pso)
574 {
575         tPChanFCurveLink *pfl;
576         
577         /* iterate over each pose-channel affected, restoring all channels to their original values */
578         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
579                 bPoseChannel *pchan= pfl->pchan;
580                 
581                 /* just copy all the values over regardless of whether they changed or not */
582                 VECCOPY(pchan->loc, pfl->oldloc);
583                 VECCOPY(pchan->eul, pfl->oldrot);
584                 VECCOPY(pchan->size, pfl->oldscale);
585                 QUATCOPY(pchan->quat, pfl->oldquat);
586         }
587 }
588
589 /* ------------------------------------ */
590
591 /* common code for invoke() methods */
592 static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
593 {
594         tPChanFCurveLink *pfl;
595         AnimData *adt= pso->ob->adt;
596         wmWindow *win= CTX_wm_window(C);
597         
598         /* for each link, add all its keyframes to the search tree */
599         for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) {
600                 LinkData *ld;
601                 
602                 /* do this for each F-Curve */
603                 for (ld= pfl->fcurves.first; ld; ld= ld->next) {
604                         FCurve *fcu= (FCurve *)ld->data;
605                         fcurve_to_keylist(adt, fcu, &pso->keys, NULL);
606                 }
607         }
608         
609         /* consolidate these keyframes, and figure out the nearest ones */
610         BLI_dlrbTree_linkedlist_sync(&pso->keys);
611         
612                 /* cancel if no keyframes found... */
613         if (pso->keys.root) {
614                 ActKeyColumn *ak;
615                 
616                 /* firstly, check if the current frame is a keyframe... */
617                 ak= cfra_find_actkeycolumn(pso->keys.root, pso->cframe);
618                 
619                 if (ak == NULL) {
620                         /* current frame is not a keyframe, so search */
621                         ActKeyColumn *pk= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 0);
622                         ActKeyColumn *nk= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 1);
623                         
624                         /* check if we found good keyframes */
625                         if ((pk == nk) && (pk != NULL)) {
626                                 if (pk->cfra < pso->cframe)
627                                         nk= nk->next;
628                                 else if (nk->cfra > pso->cframe)
629                                         pk= pk->prev;
630                         }
631                         
632                         /* new set the frames */
633                                 /* prev frame */
634                         pso->prevFrame= (pk)? (pk->cfra) : (pso->cframe - 1);
635                         RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
636                                 /* next frame */
637                         pso->nextFrame= (nk)? (nk->cfra) : (pso->cframe + 1);
638                         RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
639                 }
640                 else {
641                         /* current frame itself is a keyframe, so just take keyframes on either side */
642                                 /* prev frame */
643                         pso->prevFrame= (ak->prev)? (ak->prev->cfra) : (pso->cframe - 1);
644                         RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
645                                 /* next frame */
646                         pso->nextFrame= (ak->next)? (ak->next->cfra) : (pso->cframe + 1);
647                         RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
648                 }
649         }
650         else {
651                 BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between.");
652                 return OPERATOR_CANCELLED;
653         }
654         
655         /* initial apply for operator... */
656         // TODO: need to calculate percentage for initial round too...
657         pose_slide_apply(C, op, pso);
658         
659         /* depsgraph updates + redraws */
660         pose_slide_refresh(C, pso);
661         
662         /* set cursor to indicate modal */
663         WM_cursor_modal(win, BC_EW_SCROLLCURSOR);
664         
665         /* add a modal handler for this operator */
666         WM_event_add_modal_handler(C, op);
667         return OPERATOR_RUNNING_MODAL;
668 }
669
670 /* common code for modal() */
671 static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt)
672 {
673         tPoseSlideOp *pso= op->customdata;
674         wmWindow *win= CTX_wm_window(C);
675         
676         switch (evt->type) {
677                 case LEFTMOUSE: /* confirm */
678                 {
679                         /* return to normal cursor */
680                         WM_cursor_restore(win);
681                         
682                         /* insert keyframes as required... */
683                         pose_slide_autoKeyframe(C, pso);
684                         pose_slide_exit(C, op);
685                         
686                         /* done! */
687                         return OPERATOR_FINISHED;
688                 }
689                 
690                 case ESCKEY:    /* cancel */
691                 case RIGHTMOUSE: 
692                 {
693                         /* return to normal cursor */
694                         WM_cursor_restore(win);
695                         
696                         /* reset transforms back to original state */
697                         pose_slide_reset(C, pso);
698                         
699                         /* depsgraph updates + redraws */
700                         pose_slide_refresh(C, pso);
701                         
702                         /* clean up temp data */
703                         pose_slide_exit(C, op);
704                         
705                         /* cancelled! */
706                         return OPERATOR_CANCELLED;
707                 }
708                         
709                 case MOUSEMOVE: /* calculate new position */
710                 {
711                         /* calculate percentage based on position of mouse (we only use x-axis for now.
712                          * since this is more conveninent for users to do), and store new percentage value 
713                          */
714                         pso->percentage= (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
715                         RNA_float_set(op->ptr, "percentage", pso->percentage);
716                         
717                         /* reset transforms (to avoid accumulation errors) */
718                         pose_slide_reset(C, pso);
719                         
720                         /* apply... */
721                         pose_slide_apply(C, op, pso);
722                 }
723                         break;
724         }
725         
726         /* still running... */
727         return OPERATOR_RUNNING_MODAL;
728 }
729
730 /* common code for cancel() */
731 static int pose_slide_cancel (bContext *C, wmOperator *op)
732 {
733         /* cleanup and done */
734         pose_slide_exit(C, op);
735         return OPERATOR_CANCELLED;
736 }
737
738 /* common code for exec() methods */
739 static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
740 {
741         /* settings should have been set up ok for applying, so just apply! */
742         pose_slide_apply(C, op, pso);
743         
744         /* insert keyframes if needed */
745         pose_slide_autoKeyframe(C, pso);
746         
747         /* cleanup and done */
748         pose_slide_exit(C, op);
749         
750         return OPERATOR_FINISHED;
751 }
752
753 /* common code for defining RNA properties */
754 static void pose_slide_opdef_properties (wmOperatorType *ot)
755 {
756         RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame.", 0, 50);
757         RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame.", 0, 50);
758         RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7);
759 }
760
761 /* ------------------------------------ */
762
763 /* invoke() - for 'push' mode */
764 static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt)
765 {
766         tPoseSlideOp *pso;
767         
768         /* initialise data  */
769         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
770                 pose_slide_exit(C, op);
771                 return OPERATOR_CANCELLED;
772         }
773         else
774                 pso= op->customdata;
775         
776         /* do common setup work */
777         return pose_slide_invoke_common(C, op, pso);
778 }
779
780 /* exec() - for push */
781 static int pose_slide_push_exec (bContext *C, wmOperator *op)
782 {
783         tPoseSlideOp *pso;
784         
785         /* initialise data (from RNA-props) */
786         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
787                 pose_slide_exit(C, op);
788                 return OPERATOR_CANCELLED;
789         }
790         else
791                 pso= op->customdata;
792                 
793         /* do common exec work */
794         return pose_slide_exec_common(C, op, pso);
795 }
796
797 void POSE_OT_push (wmOperatorType *ot)
798 {
799         /* identifiers */
800         ot->name= "Push Pose";
801         ot->idname= "POSE_OT_push";
802         ot->description= "Exaggerate the current pose";
803         
804         /* callbacks */
805         ot->exec= pose_slide_push_exec;
806         ot->invoke= pose_slide_push_invoke;
807         ot->modal= pose_slide_modal;
808         ot->cancel= pose_slide_cancel;
809         ot->poll= ED_operator_posemode;
810         
811         /* flags */
812         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
813         
814         /* Properties */
815         pose_slide_opdef_properties(ot);
816 }
817
818 /* ........................ */
819
820 /* invoke() - for 'relax' mode */
821 static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt)
822 {
823         tPoseSlideOp *pso;
824         
825         /* initialise data  */
826         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
827                 pose_slide_exit(C, op);
828                 return OPERATOR_CANCELLED;
829         }
830         else
831                 pso= op->customdata;
832         
833         /* do common setup work */
834         return pose_slide_invoke_common(C, op, pso);
835 }
836
837 /* exec() - for relax */
838 static int pose_slide_relax_exec (bContext *C, wmOperator *op)
839 {
840         tPoseSlideOp *pso;
841         
842         /* initialise data (from RNA-props) */
843         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
844                 pose_slide_exit(C, op);
845                 return OPERATOR_CANCELLED;
846         }
847         else
848                 pso= op->customdata;
849                 
850         /* do common exec work */
851         return pose_slide_exec_common(C, op, pso);
852 }
853
854 void POSE_OT_relax (wmOperatorType *ot)
855 {
856         /* identifiers */
857         ot->name= "Relax Pose";
858         ot->idname= "POSE_OT_relax";
859         ot->description= "Make the current pose more similar to its surrounding ones.";
860         
861         /* callbacks */
862         ot->exec= pose_slide_relax_exec;
863         ot->invoke= pose_slide_relax_invoke;
864         ot->modal= pose_slide_modal;
865         ot->cancel= pose_slide_cancel;
866         ot->poll= ED_operator_posemode;
867         
868         /* flags */
869         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
870         
871         /* Properties */
872         pose_slide_opdef_properties(ot);
873 }
874
875 /* ........................ */
876
877 /* invoke() - for 'breakdown' mode */
878 static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt)
879 {
880         tPoseSlideOp *pso;
881         
882         /* initialise data  */
883         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
884                 pose_slide_exit(C, op);
885                 return OPERATOR_CANCELLED;
886         }
887         else
888                 pso= op->customdata;
889         
890         /* do common setup work */
891         return pose_slide_invoke_common(C, op, pso);
892 }
893
894 /* exec() - for breakdown */
895 static int pose_slide_breakdown_exec (bContext *C, wmOperator *op)
896 {
897         tPoseSlideOp *pso;
898         
899         /* initialise data (from RNA-props) */
900         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
901                 pose_slide_exit(C, op);
902                 return OPERATOR_CANCELLED;
903         }
904         else
905                 pso= op->customdata;
906                 
907         /* do common exec work */
908         return pose_slide_exec_common(C, op, pso);
909 }
910
911 void POSE_OT_breakdown (wmOperatorType *ot)
912 {
913         /* identifiers */
914         ot->name= "Pose Breakdowner";
915         ot->idname= "POSE_OT_breakdown";
916         ot->description= "Create a suitable breakdown pose on the current frame.";
917         
918         /* callbacks */
919         ot->exec= pose_slide_breakdown_exec;
920         ot->invoke= pose_slide_breakdown_invoke;
921         ot->modal= pose_slide_modal;
922         ot->cancel= pose_slide_cancel;
923         ot->poll= ED_operator_posemode;
924         
925         /* flags */
926         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
927         
928         /* Properties */
929         pose_slide_opdef_properties(ot);
930 }
931
932 /* **************************************************** */