Merge of itasc branch. Project files, scons and cmake should be working. Makefile...
[blender-staging.git] / source / blender / editors / armature / poseSlide.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 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                 default: /* unhandled event (maybe it was some view manip? */
726                         /* allow to pass through */
727                         return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH;
728         }
729         
730         /* still running... */
731         return OPERATOR_RUNNING_MODAL;
732 }
733
734 /* common code for cancel() */
735 static int pose_slide_cancel (bContext *C, wmOperator *op)
736 {
737         /* cleanup and done */
738         pose_slide_exit(C, op);
739         return OPERATOR_CANCELLED;
740 }
741
742 /* common code for exec() methods */
743 static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
744 {
745         /* settings should have been set up ok for applying, so just apply! */
746         pose_slide_apply(C, op, pso);
747         
748         /* insert keyframes if needed */
749         pose_slide_autoKeyframe(C, pso);
750         
751         /* cleanup and done */
752         pose_slide_exit(C, op);
753         
754         return OPERATOR_FINISHED;
755 }
756
757 /* common code for defining RNA properties */
758 static void pose_slide_opdef_properties (wmOperatorType *ot)
759 {
760         RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame.", 0, 50);
761         RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame.", 0, 50);
762         RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7);
763 }
764
765 /* ------------------------------------ */
766
767 /* invoke() - for 'push' mode */
768 static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt)
769 {
770         tPoseSlideOp *pso;
771         
772         /* initialise data  */
773         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
774                 pose_slide_exit(C, op);
775                 return OPERATOR_CANCELLED;
776         }
777         else
778                 pso= op->customdata;
779         
780         /* do common setup work */
781         return pose_slide_invoke_common(C, op, pso);
782 }
783
784 /* exec() - for push */
785 static int pose_slide_push_exec (bContext *C, wmOperator *op)
786 {
787         tPoseSlideOp *pso;
788         
789         /* initialise data (from RNA-props) */
790         if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
791                 pose_slide_exit(C, op);
792                 return OPERATOR_CANCELLED;
793         }
794         else
795                 pso= op->customdata;
796                 
797         /* do common exec work */
798         return pose_slide_exec_common(C, op, pso);
799 }
800
801 void POSE_OT_push (wmOperatorType *ot)
802 {
803         /* identifiers */
804         ot->name= "Push Pose";
805         ot->idname= "POSE_OT_push";
806         ot->description= "Exaggerate the current pose";
807         
808         /* callbacks */
809         ot->exec= pose_slide_push_exec;
810         ot->invoke= pose_slide_push_invoke;
811         ot->modal= pose_slide_modal;
812         ot->cancel= pose_slide_cancel;
813         ot->poll= ED_operator_posemode;
814         
815         /* flags */
816         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
817         
818         /* Properties */
819         pose_slide_opdef_properties(ot);
820 }
821
822 /* ........................ */
823
824 /* invoke() - for 'relax' mode */
825 static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt)
826 {
827         tPoseSlideOp *pso;
828         
829         /* initialise data  */
830         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
831                 pose_slide_exit(C, op);
832                 return OPERATOR_CANCELLED;
833         }
834         else
835                 pso= op->customdata;
836         
837         /* do common setup work */
838         return pose_slide_invoke_common(C, op, pso);
839 }
840
841 /* exec() - for relax */
842 static int pose_slide_relax_exec (bContext *C, wmOperator *op)
843 {
844         tPoseSlideOp *pso;
845         
846         /* initialise data (from RNA-props) */
847         if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
848                 pose_slide_exit(C, op);
849                 return OPERATOR_CANCELLED;
850         }
851         else
852                 pso= op->customdata;
853                 
854         /* do common exec work */
855         return pose_slide_exec_common(C, op, pso);
856 }
857
858 void POSE_OT_relax (wmOperatorType *ot)
859 {
860         /* identifiers */
861         ot->name= "Relax Pose";
862         ot->idname= "POSE_OT_relax";
863         ot->description= "Make the current pose more similar to its surrounding ones.";
864         
865         /* callbacks */
866         ot->exec= pose_slide_relax_exec;
867         ot->invoke= pose_slide_relax_invoke;
868         ot->modal= pose_slide_modal;
869         ot->cancel= pose_slide_cancel;
870         ot->poll= ED_operator_posemode;
871         
872         /* flags */
873         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
874         
875         /* Properties */
876         pose_slide_opdef_properties(ot);
877 }
878
879 /* ........................ */
880
881 /* invoke() - for 'breakdown' mode */
882 static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt)
883 {
884         tPoseSlideOp *pso;
885         
886         /* initialise data  */
887         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
888                 pose_slide_exit(C, op);
889                 return OPERATOR_CANCELLED;
890         }
891         else
892                 pso= op->customdata;
893         
894         /* do common setup work */
895         return pose_slide_invoke_common(C, op, pso);
896 }
897
898 /* exec() - for breakdown */
899 static int pose_slide_breakdown_exec (bContext *C, wmOperator *op)
900 {
901         tPoseSlideOp *pso;
902         
903         /* initialise data (from RNA-props) */
904         if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
905                 pose_slide_exit(C, op);
906                 return OPERATOR_CANCELLED;
907         }
908         else
909                 pso= op->customdata;
910                 
911         /* do common exec work */
912         return pose_slide_exec_common(C, op, pso);
913 }
914
915 void POSE_OT_breakdown (wmOperatorType *ot)
916 {
917         /* identifiers */
918         ot->name= "Pose Breakdowner";
919         ot->idname= "POSE_OT_breakdown";
920         ot->description= "Create a suitable breakdown pose on the current frame.";
921         
922         /* callbacks */
923         ot->exec= pose_slide_breakdown_exec;
924         ot->invoke= pose_slide_breakdown_invoke;
925         ot->modal= pose_slide_modal;
926         ot->cancel= pose_slide_cancel;
927         ot->poll= ED_operator_posemode;
928         
929         /* flags */
930         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
931         
932         /* Properties */
933         pose_slide_opdef_properties(ot);
934 }
935
936 /* **************************************************** */