Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / armature / pose_slide.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
17  * This is a new part of Blender
18  */
19
20 /** \file
21  * \ingroup edarmature
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_math.h"
27 #include "BLI_blenlib.h"
28 #include "BLI_dlrbTree.h"
29
30 #include "DNA_anim_types.h"
31 #include "DNA_armature_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "BKE_fcurve.h"
36 #include "BKE_nla.h"
37
38 #include "BKE_context.h"
39 #include "BKE_layer.h"
40 #include "BKE_object.h"
41 #include "BKE_report.h"
42 #include "BKE_unit.h"
43
44 #include "RNA_access.h"
45 #include "RNA_define.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "UI_interface.h"
51
52 #include "ED_armature.h"
53 #include "ED_keyframes_draw.h"
54 #include "ED_markers.h"
55 #include "ED_numinput.h"
56 #include "ED_screen.h"
57
58 #include "armature_intern.h"
59
60 /* **************************************************** */
61 /* == POSE 'SLIDING' TOOLS ==
62  *
63  * A) Push & Relax, Breakdowner
64  * These tools provide the animator with various capabilities
65  * for interactively controlling the spacing of poses, but also
66  * for 'pushing' and/or 'relaxing' extremes as they see fit.
67  *
68  * B) Propagate
69  * This tool copies elements of the selected pose to successive
70  * keyframes, allowing the animator to go back and modify the poses
71  * for some "static" pose controls, without having to repeatedly
72  * doing a "next paste" dance.
73  *
74  * C) Pose Sculpting
75  * This is yet to be implemented, but the idea here is to use
76  * sculpting techniques to make it easier to pose rigs by allowing
77  * rigs to be manipulated using a familiar paint-based interface.
78  */
79 /* **************************************************** */
80 /* A) Push & Relax, Breakdowner */
81
82 /* Temporary data shared between these operators */
83 typedef struct tPoseSlideOp {
84   /** current scene */
85   Scene *scene;
86   /** area that we're operating in (needed for modal()) */
87   ScrArea *sa;
88   /** region that we're operating in (needed for modal()) */
89   ARegion *ar;
90   /** len of the PoseSlideObject array. */
91   uint objects_len;
92
93   /** links between posechannels and f-curves for all the pose objects. */
94   ListBase pfLinks;
95   /** binary tree for quicker searching for keyframes (when applicable) */
96   DLRBT_Tree keys;
97
98   /** current frame number - global time */
99   int cframe;
100
101   /** frame before current frame (blend-from) - global time */
102   int prevFrame;
103   /** frame after current frame (blend-to)    - global time */
104   int nextFrame;
105
106   /** sliding mode (ePoseSlide_Modes) */
107   short mode;
108   /** unused for now, but can later get used for storing runtime settings.... */
109   short flag;
110
111   /** which transforms/channels are affected (ePoseSlide_Channels) */
112   short channels;
113   /** axis-limits for transforms (ePoseSlide_AxisLock) */
114   short axislock;
115
116   /** 0-1 value for determining the influence of whatever is relevant */
117   float percentage;
118
119   /** numeric input */
120   NumInput num;
121
122   struct tPoseSlideObject *ob_data_array;
123 } tPoseSlideOp;
124
125 typedef struct tPoseSlideObject {
126   Object *ob;       /* active object that Pose Info comes from */
127   float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
128   float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
129   bool valid;
130 } tPoseSlideObject;
131
132 /* Pose Sliding Modes */
133 typedef enum ePoseSlide_Modes {
134   POSESLIDE_PUSH = 0,  /* exaggerate the pose... */
135   POSESLIDE_RELAX,     /* soften the pose... */
136   POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
137 } ePoseSlide_Modes;
138
139 /* Transforms/Channels to Affect */
140 typedef enum ePoseSlide_Channels {
141   PS_TFM_ALL = 0, /* All transforms and properties */
142
143   PS_TFM_LOC, /* Loc/Rot/Scale */
144   PS_TFM_ROT,
145   PS_TFM_SIZE,
146
147   PS_TFM_BBONE_SHAPE, /* Bendy Bones */
148
149   PS_TFM_PROPS, /* Custom Properties */
150 } ePoseSlide_Channels;
151
152 /* Property enum for ePoseSlide_Channels */
153 static const EnumPropertyItem prop_channels_types[] = {
154     {PS_TFM_ALL,
155      "ALL",
156      0,
157      "All Properties",
158      "All properties, including transforms, bendy bone shape, and custom properties"},
159     {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
160     {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
161     {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
162     {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
163     {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
164     {0, NULL, 0, NULL, NULL},
165 };
166
167 /* Axis Locks */
168 typedef enum ePoseSlide_AxisLock {
169   PS_LOCK_X = (1 << 0),
170   PS_LOCK_Y = (1 << 1),
171   PS_LOCK_Z = (1 << 2),
172 } ePoseSlide_AxisLock;
173
174 /* Property enum for ePoseSlide_AxisLock */
175 static const EnumPropertyItem prop_axis_lock_types[] = {
176     {0, "FREE", 0, "Free", "All axes are affected"},
177     {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
178     {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
179     {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
180     /* TODO: Combinations? */
181     {0, NULL, 0, NULL, NULL},
182 };
183
184 /* ------------------------------------ */
185
186 /* operator init */
187 static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
188 {
189   tPoseSlideOp *pso;
190
191   /* init slide-op data */
192   pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
193
194   /* get info from context */
195   pso->scene = CTX_data_scene(C);
196   pso->sa = CTX_wm_area(C);   /* only really needed when doing modal() */
197   pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
198
199   pso->cframe = pso->scene->r.cfra;
200   pso->mode = mode;
201
202   /* set range info from property values - these may get overridden for the invoke() */
203   pso->percentage = RNA_float_get(op->ptr, "percentage");
204   pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
205   pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
206
207   /* get the set of properties/axes that can be operated on */
208   pso->channels = RNA_enum_get(op->ptr, "channels");
209   pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
210
211   /* for each Pose-Channel which gets affected, get the F-Curves for that channel
212    * and set the relevant transform flags... */
213   poseAnim_mapping_get(C, &pso->pfLinks);
214
215   Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
216       CTX_data_view_layer(C), CTX_wm_view3d(C), &pso->objects_len, OB_MODE_POSE);
217   pso->ob_data_array = MEM_callocN(pso->objects_len * sizeof(tPoseSlideObject),
218                                    "pose slide objects data");
219
220   for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
221     tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
222     Object *ob_iter = poseAnim_object_get(objects[ob_index]);
223
224     /* Ensure validity of the settings from the context. */
225     if (ob_iter == NULL) {
226       continue;
227     }
228
229     ob_data->ob = ob_iter;
230     ob_data->valid = true;
231
232     /* apply NLA mapping corrections so the frame lookups work */
233     ob_data->prevFrameF = BKE_nla_tweakedit_remap(
234         ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
235     ob_data->nextFrameF = BKE_nla_tweakedit_remap(
236         ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
237
238     /* set depsgraph flags */
239     /* make sure the lock is set OK, unlock can be accidentally saved? */
240     ob_data->ob->pose->flag |= POSE_LOCKED;
241     ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
242   }
243   MEM_freeN(objects);
244
245   /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
246    * to the caller of this (usually only invoke() will do it, to make things more efficient).
247    */
248   BLI_dlrbTree_init(&pso->keys);
249
250   /* initialise numeric input */
251   initNumInput(&pso->num);
252   pso->num.idx_max = 0; /* one axis */
253   pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
254   pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
255
256   /* return status is whether we've got all the data we were requested to get */
257   return 1;
258 }
259
260 /* exiting the operator - free data */
261 static void pose_slide_exit(wmOperator *op)
262 {
263   tPoseSlideOp *pso = op->customdata;
264
265   /* if data exists, clear its data and exit */
266   if (pso) {
267     /* free the temp pchan links and their data */
268     poseAnim_mapping_free(&pso->pfLinks);
269
270     /* free RB-BST for keyframes (if it contained data) */
271     BLI_dlrbTree_free(&pso->keys);
272
273     if (pso->ob_data_array != NULL) {
274       MEM_freeN(pso->ob_data_array);
275     }
276
277     /* free data itself */
278     MEM_freeN(pso);
279   }
280
281   /* cleanup */
282   op->customdata = NULL;
283 }
284
285 /* ------------------------------------ */
286
287 /* helper for apply() / reset() - refresh the data */
288 static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
289 {
290   /* wrapper around the generic version, allowing us to add some custom stuff later still */
291   for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
292     tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
293     if (ob_data->valid) {
294       poseAnim_mapping_refresh(C, pso->scene, ob_data->ob);
295     }
296   }
297 }
298
299 /**
300  * Although this lookup is not ideal, we won't be dealing with a lot of objects at a given time.
301  * But if it comes to that we can instead store prev/next frame in the #tPChanFCurveLink.
302  */
303 static bool pose_frame_range_from_object_get(tPoseSlideOp *pso,
304                                              Object *ob,
305                                              float *prevFrameF,
306                                              float *nextFrameF)
307 {
308   for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
309     tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
310     Object *ob_iter = ob_data->ob;
311
312     if (ob_iter == ob) {
313       *prevFrameF = ob_data->prevFrameF;
314       *nextFrameF = ob_data->nextFrameF;
315       return true;
316     }
317   }
318   *prevFrameF = *nextFrameF = 0.0f;
319   return false;
320 }
321
322 /* helper for apply() - perform sliding for some value */
323 static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, float *val)
324 {
325   float prevFrameF, nextFrameF;
326   float cframe = (float)pso->cframe;
327   float sVal, eVal;
328   float w1, w2;
329
330   pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
331
332   /* get keyframe values for endpoint poses to blend with */
333   /* previous/start */
334   sVal = evaluate_fcurve(fcu, prevFrameF);
335   /* next/end */
336   eVal = evaluate_fcurve(fcu, nextFrameF);
337
338   /* if both values are equal, don't do anything */
339   if (IS_EQF(sVal, eVal)) {
340     (*val) = sVal;
341     return;
342   }
343
344   /* calculate the relative weights of the endpoints */
345   if (pso->mode == POSESLIDE_BREAKDOWN) {
346     /* get weights from the percentage control */
347     w1 = pso->percentage; /* this must come second */
348     w2 = 1.0f - w1;       /* this must come first */
349   }
350   else {
351     /* - these weights are derived from the relative distance of these
352      *   poses from the current frame
353      * - they then get normalized so that they only sum up to 1
354      */
355     float wtot;
356
357     w1 = cframe - (float)pso->prevFrame;
358     w2 = (float)pso->nextFrame - cframe;
359
360     wtot = w1 + w2;
361     w1 = (w1 / wtot);
362     w2 = (w2 / wtot);
363   }
364
365   /* depending on the mode, calculate the new value
366    * - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
367    *   since multiplication in another order would decrease the value the current frame is closer to
368    */
369   switch (pso->mode) {
370     case POSESLIDE_PUSH: /* make the current pose more pronounced */
371     {
372       /* perform a weighted average here, favoring the middle pose
373        * - numerator should be larger than denominator to 'expand' the result
374        * - perform this weighting a number of times given by the percentage...
375        */
376       /* TODO: maybe a sensitivity ctrl on top of this is needed */
377       int iters = (int)ceil(10.0f * pso->percentage);
378
379       while (iters-- > 0) {
380         (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f;
381       }
382       break;
383     }
384     case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
385     {
386       /* perform a weighted average here, favoring the middle pose
387        * - numerator should be smaller than denominator to 'relax' the result
388        * - perform this weighting a number of times given by the percentage...
389        */
390       /* TODO: maybe a sensitivity ctrl on top of this is needed */
391       int iters = (int)ceil(10.0f * pso->percentage);
392
393       while (iters-- > 0) {
394         (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f;
395       }
396       break;
397     }
398     case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
399     {
400       /* Perform simple linear interpolation -
401        * coefficient for start must come from pso->percentage. */
402       /* TODO: make this use some kind of spline interpolation instead? */
403       (*val) = ((sVal * w2) + (eVal * w1));
404       break;
405     }
406   }
407 }
408
409 /* helper for apply() - perform sliding for some 3-element vector */
410 static void pose_slide_apply_vec3(tPoseSlideOp *pso,
411                                   tPChanFCurveLink *pfl,
412                                   float vec[3],
413                                   const char propName[])
414 {
415   LinkData *ld = NULL;
416   char *path = NULL;
417
418   /* get the path to use... */
419   path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
420
421   /* using this path, find each matching F-Curve for the variables we're interested in */
422   while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
423     FCurve *fcu = (FCurve *)ld->data;
424     const int idx = fcu->array_index;
425     const int lock = pso->axislock;
426
427     /* check if this F-Curve is ok given the current axis locks */
428     BLI_assert(fcu->array_index < 3);
429
430     if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
431         ((lock & PS_LOCK_Z) && (idx == 2))) {
432       /* just work on these channels one by one... there's no interaction between values */
433       pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
434     }
435   }
436
437   /* free the temp path we got */
438   MEM_freeN(path);
439 }
440
441 /* helper for apply() - perform sliding for custom properties or bbone properties */
442 static void pose_slide_apply_props(tPoseSlideOp *pso,
443                                    tPChanFCurveLink *pfl,
444                                    const char prop_prefix[])
445 {
446   PointerRNA ptr = {{NULL}};
447   LinkData *ld;
448   int len = strlen(pfl->pchan_path);
449
450   /* setup pointer RNA for resolving paths */
451   RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
452
453   /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
454    *   so just check for opening pair after the end of the path
455    * - bbone properties are similar, but they always start with a prefix "bbone_*",
456    *   so a similar method should work here for those too
457    */
458   for (ld = pfl->fcurves.first; ld; ld = ld->next) {
459     FCurve *fcu = (FCurve *)ld->data;
460     const char *bPtr, *pPtr;
461
462     if (fcu->rna_path == NULL) {
463       continue;
464     }
465
466     /* do we have a match?
467      * - bPtr is the RNA Path with the standard part chopped off
468      * - pPtr is the chunk of the path which is left over
469      */
470     bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
471     pPtr = strstr(bPtr, prop_prefix);
472
473     if (pPtr) {
474       /* use RNA to try and get a handle on this property, then, assuming that it is just
475        * numerical, try and grab the value as a float for temp editing before setting back
476        */
477       PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
478
479       if (prop) {
480         switch (RNA_property_type(prop)) {
481           /* continuous values that can be smoothly interpolated... */
482           case PROP_FLOAT: {
483             float tval = RNA_property_float_get(&ptr, prop);
484             pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
485             RNA_property_float_set(&ptr, prop, tval);
486             break;
487           }
488           case PROP_INT: {
489             float tval = (float)RNA_property_int_get(&ptr, prop);
490             pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
491             RNA_property_int_set(&ptr, prop, (int)tval);
492             break;
493           }
494
495           /* values which can only take discrete values */
496           case PROP_BOOLEAN: {
497             float tval = (float)RNA_property_boolean_get(&ptr, prop);
498             pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
499             RNA_property_boolean_set(
500                 &ptr, prop, (int)tval);  // XXX: do we need threshold clamping here?
501             break;
502           }
503           case PROP_ENUM: {
504             /* don't handle this case - these don't usually represent interchangeable
505              * set of values which should be interpolated between
506              */
507             break;
508           }
509
510           default:
511             /* cannot handle */
512             //printf("Cannot Pose Slide non-numerical property\n");
513             break;
514         }
515       }
516     }
517   }
518 }
519
520 /* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
521 static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
522 {
523   FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
524   bPoseChannel *pchan = pfl->pchan;
525   LinkData *ld = NULL;
526   char *path = NULL;
527   float cframe;
528   float prevFrameF, nextFrameF;
529
530   if (!pose_frame_range_from_object_get(pso, pfl->ob, &prevFrameF, &nextFrameF)) {
531     BLI_assert(!"Invalid pfl data");
532     return;
533   }
534
535   /* get the path to use - this should be quaternion rotations only (needs care) */
536   path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
537
538   /* get the current frame number */
539   cframe = (float)pso->cframe;
540
541   /* using this path, find each matching F-Curve for the variables we're interested in */
542   while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
543     FCurve *fcu = (FCurve *)ld->data;
544
545     /* assign this F-Curve to one of the relevant pointers... */
546     switch (fcu->array_index) {
547       case 3: /* z */
548         fcu_z = fcu;
549         break;
550       case 2: /* y */
551         fcu_y = fcu;
552         break;
553       case 1: /* x */
554         fcu_x = fcu;
555         break;
556       case 0: /* w */
557         fcu_w = fcu;
558         break;
559     }
560   }
561
562   /* only if all channels exist, proceed */
563   if (fcu_w && fcu_x && fcu_y && fcu_z) {
564     float quat_prev[4], quat_prev_orig[4];
565     float quat_next[4], quat_next_orig[4];
566     float quat_curr[4], quat_curr_orig[4];
567     float quat_final[4];
568
569     copy_qt_qt(quat_curr_orig, pchan->quat);
570
571     /* get 2 quats */
572     quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
573     quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
574     quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
575     quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
576
577     quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
578     quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
579     quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
580     quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
581
582     normalize_qt_qt(quat_prev, quat_prev_orig);
583     normalize_qt_qt(quat_next, quat_next_orig);
584     normalize_qt_qt(quat_curr, quat_curr_orig);
585
586     /* perform blending */
587     if (pso->mode == POSESLIDE_BREAKDOWN) {
588       /* Just perform the interpol between quat_prev and
589        * quat_next using pso->percentage as a guide. */
590       interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
591     }
592     else if (pso->mode == POSESLIDE_PUSH) {
593       float quat_diff[4];
594
595       /* calculate the delta transform from the previous to the current */
596       /* TODO: investigate ways to favour one transform more? */
597       sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
598
599       /* increase the original by the delta transform, by an amount determined by percentage */
600       add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
601
602       normalize_qt(quat_final);
603     }
604     else {
605       BLI_assert(pso->mode == POSESLIDE_RELAX);
606       float quat_interp[4], quat_final_prev[4];
607       /* TODO: maybe a sensitivity ctrl on top of this is needed */
608       int iters = (int)ceil(10.0f * pso->percentage);
609
610       copy_qt_qt(quat_final, quat_curr);
611
612       /* perform this blending several times until a satisfactory result is reached */
613       while (iters-- > 0) {
614         /* calculate the interpolation between the endpoints */
615         interp_qt_qtqt(quat_interp,
616                        quat_prev,
617                        quat_next,
618                        (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
619
620         normalize_qt_qt(quat_final_prev, quat_final);
621
622         /* tricky interpolations - blending between original and new */
623         interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
624       }
625     }
626
627     /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
628     quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
629   }
630
631   /* free the path now */
632   MEM_freeN(path);
633 }
634
635 /* apply() - perform the pose sliding based on weighting various poses */
636 static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
637 {
638   tPChanFCurveLink *pfl;
639
640   /* sanitise the frame ranges */
641   if (pso->prevFrame == pso->nextFrame) {
642     /* move out one step either side */
643     pso->prevFrame--;
644     pso->nextFrame++;
645
646     for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
647       tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
648
649       if (!ob_data->valid) {
650         continue;
651       }
652
653       /* apply NLA mapping corrections so the frame lookups work */
654       ob_data->prevFrameF = BKE_nla_tweakedit_remap(
655           ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
656       ob_data->nextFrameF = BKE_nla_tweakedit_remap(
657           ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
658     }
659   }
660
661   /* for each link, handle each set of transforms */
662   for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
663     /* valid transforms for each PoseChannel should have been noted already
664      * - sliding the pose should be a straightforward exercise for location+rotation,
665      *   but rotations get more complicated since we may want to use quaternion blending
666      *   for quaternions instead...
667      */
668     bPoseChannel *pchan = pfl->pchan;
669
670     if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
671       /* calculate these for the 'location' vector, and use location curves */
672       pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
673     }
674
675     if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
676       /* calculate these for the 'scale' vector, and use scale curves */
677       pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
678     }
679
680     if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
681       /* everything depends on the rotation mode */
682       if (pchan->rotmode > 0) {
683         /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
684         pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
685       }
686       else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
687         /* TODO: need to figure out how to do this! */
688       }
689       else {
690         /* quaternions - use quaternion blending */
691         pose_slide_apply_quat(pso, pfl);
692       }
693     }
694
695     if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
696       /* bbone properties - they all start a "bbone_" prefix */
697       pose_slide_apply_props(pso, pfl, "bbone_");
698     }
699
700     if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
701       /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
702        * (e.g. the facial rigs used in Sintel)
703        */
704       pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
705     }
706   }
707
708   /* depsgraph updates + redraws */
709   pose_slide_refresh(C, pso);
710 }
711
712 /* perform auto-key-framing after changes were made + confirmed */
713 static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
714 {
715   /* wrapper around the generic call */
716   poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
717 }
718
719 /* reset changes made to current pose */
720 static void pose_slide_reset(tPoseSlideOp *pso)
721 {
722   /* wrapper around the generic call, so that custom stuff can be added later */
723   poseAnim_mapping_reset(&pso->pfLinks);
724 }
725
726 /* ------------------------------------ */
727
728 /* draw percentage indicator in header */
729 // TODO: Include hints about locks here...
730 static void pose_slide_draw_status(tPoseSlideOp *pso)
731 {
732   char status_str[UI_MAX_DRAW_STR];
733   char limits_str[UI_MAX_DRAW_STR];
734   char axis_str[50];
735   char mode_str[32];
736
737   switch (pso->mode) {
738     case POSESLIDE_PUSH:
739       strcpy(mode_str, "Push Pose");
740       break;
741     case POSESLIDE_RELAX:
742       strcpy(mode_str, "Relax Pose");
743       break;
744     case POSESLIDE_BREAKDOWN:
745       strcpy(mode_str, "Breakdown");
746       break;
747
748     default:
749       /* unknown */
750       strcpy(mode_str, "Sliding-Tool");
751       break;
752   }
753
754   switch (pso->axislock) {
755     case PS_LOCK_X:
756       BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
757       break;
758     case PS_LOCK_Y:
759       BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
760       break;
761     case PS_LOCK_Z:
762       BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
763       break;
764
765     default:
766       if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
767         BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
768       }
769       else {
770         axis_str[0] = '\0';
771       }
772       break;
773   }
774
775   switch (pso->channels) {
776     case PS_TFM_LOC:
777       BLI_snprintf(limits_str,
778                    sizeof(limits_str),
779                    "[G]/R/S/B/C - Location only (G to clear) | %s",
780                    axis_str);
781       break;
782     case PS_TFM_ROT:
783       BLI_snprintf(limits_str,
784                    sizeof(limits_str),
785                    "G/[R]/S/B/C - Rotation only (R to clear) | %s",
786                    axis_str);
787       break;
788     case PS_TFM_SIZE:
789       BLI_snprintf(
790           limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
791       break;
792     case PS_TFM_BBONE_SHAPE:
793       BLI_strncpy(limits_str,
794                   "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s",
795                   sizeof(limits_str));
796       break;
797     case PS_TFM_PROPS:
798       BLI_strncpy(limits_str,
799                   "G/R/S/B/[C] - Custom Properties only (C to clear) | %s",
800                   sizeof(limits_str));
801       break;
802     default:
803       BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
804       break;
805   }
806
807   if (hasNumInput(&pso->num)) {
808     Scene *scene = pso->scene;
809     char str_offs[NUM_STR_REP_LEN];
810
811     outputNumInput(&pso->num, str_offs, &scene->unit);
812
813     BLI_snprintf(
814         status_str, sizeof(status_str), "%s: %s     |   %s", mode_str, str_offs, limits_str);
815   }
816   else {
817     BLI_snprintf(status_str,
818                  sizeof(status_str),
819                  "%s: %d %%     |   %s",
820                  mode_str,
821                  (int)(pso->percentage * 100.0f),
822                  limits_str);
823   }
824
825   ED_area_status_text(pso->sa, status_str);
826 }
827
828 /* common code for invoke() methods */
829 static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
830 {
831   tPChanFCurveLink *pfl;
832   wmWindow *win = CTX_wm_window(C);
833
834   /* for each link, add all its keyframes to the search tree */
835   for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
836     LinkData *ld;
837
838     /* do this for each F-Curve */
839     for (ld = pfl->fcurves.first; ld; ld = ld->next) {
840       FCurve *fcu = (FCurve *)ld->data;
841       fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
842     }
843   }
844
845   /* cancel if no keyframes found... */
846   if (pso->keys.root) {
847     ActKeyColumn *ak;
848     float cframe = (float)pso->cframe;
849
850     /* firstly, check if the current frame is a keyframe... */
851     ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
852
853     if (ak == NULL) {
854       /* current frame is not a keyframe, so search */
855       ActKeyColumn *pk = (ActKeyColumn *)BLI_dlrbTree_search_prev(
856           &pso->keys, compare_ak_cfraPtr, &cframe);
857       ActKeyColumn *nk = (ActKeyColumn *)BLI_dlrbTree_search_next(
858           &pso->keys, compare_ak_cfraPtr, &cframe);
859
860       /* new set the frames */
861       /* prev frame */
862       pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
863       RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
864       /* next frame */
865       pso->nextFrame = (nk) ? (nk->cfra) : (pso->cframe + 1);
866       RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
867     }
868     else {
869       /* current frame itself is a keyframe, so just take keyframes on either side */
870       /* prev frame */
871       pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
872       RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
873       /* next frame */
874       pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
875       RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
876     }
877
878     /* apply NLA mapping corrections so the frame lookups work */
879     for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
880       tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
881       if (ob_data->valid) {
882         ob_data->prevFrameF = BKE_nla_tweakedit_remap(
883             ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
884         ob_data->nextFrameF = BKE_nla_tweakedit_remap(
885             ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
886       }
887     }
888   }
889   else {
890     BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
891     pose_slide_exit(op);
892     return OPERATOR_CANCELLED;
893   }
894
895   /* initial apply for operator... */
896   /* TODO: need to calculate percentage for initial round too... */
897   pose_slide_apply(C, pso);
898
899   /* depsgraph updates + redraws */
900   pose_slide_refresh(C, pso);
901
902   /* set cursor to indicate modal */
903   WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
904
905   /* header print */
906   pose_slide_draw_status(pso);
907
908   /* add a modal handler for this operator */
909   WM_event_add_modal_handler(C, op);
910   return OPERATOR_RUNNING_MODAL;
911 }
912
913 /* calculate percentage based on position of mouse (we only use x-axis for now.
914  * since this is more convenient for users to do), and store new percentage value
915  */
916 static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso,
917                                                wmOperator *op,
918                                                const wmEvent *event)
919 {
920   pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
921   RNA_float_set(op->ptr, "percentage", pso->percentage);
922 }
923
924 /* handle an event to toggle channels mode */
925 static void pose_slide_toggle_channels_mode(wmOperator *op,
926                                             tPoseSlideOp *pso,
927                                             ePoseSlide_Channels channel)
928 {
929   /* Turn channel on or off? */
930   if (pso->channels == channel) {
931     /* Already limiting to transform only, so pressing this again turns it off */
932     pso->channels = PS_TFM_ALL;
933   }
934   else {
935     /* Only this set of channels */
936     pso->channels = channel;
937   }
938   RNA_enum_set(op->ptr, "channels", pso->channels);
939
940   /* Reset axis limits too for good measure */
941   pso->axislock = 0;
942   RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
943 }
944
945 /* handle an event to toggle axis locks - returns whether any change in state is needed */
946 static bool pose_slide_toggle_axis_locks(wmOperator *op,
947                                          tPoseSlideOp *pso,
948                                          ePoseSlide_AxisLock axis)
949 {
950   /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
951   if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
952     pso->axislock = 0;
953     RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
954     return false;
955   }
956
957   /* Turn on or off? */
958   if (pso->axislock == axis) {
959     /* Already limiting on this axis, so turn off */
960     pso->axislock = 0;
961   }
962   else {
963     /* Only this axis */
964     pso->axislock = axis;
965   }
966   RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
967
968   /* Setting changed, so pose update is needed */
969   return true;
970 }
971
972 /* common code for modal() */
973 static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
974 {
975   tPoseSlideOp *pso = op->customdata;
976   wmWindow *win = CTX_wm_window(C);
977   bool do_pose_update = false;
978
979   const bool has_numinput = hasNumInput(&pso->num);
980
981   switch (event->type) {
982     case LEFTMOUSE: /* confirm */
983     case RETKEY:
984     case PADENTER: {
985       /* return to normal cursor and header status */
986       ED_area_status_text(pso->sa, NULL);
987       WM_cursor_modal_restore(win);
988
989       /* insert keyframes as required... */
990       pose_slide_autoKeyframe(C, pso);
991       pose_slide_exit(op);
992
993       /* done! */
994       return OPERATOR_FINISHED;
995     }
996
997     case ESCKEY: /* cancel */
998     case RIGHTMOUSE: {
999       /* return to normal cursor and header status */
1000       ED_area_status_text(pso->sa, NULL);
1001       WM_cursor_modal_restore(win);
1002
1003       /* reset transforms back to original state */
1004       pose_slide_reset(pso);
1005
1006       /* depsgraph updates + redraws */
1007       pose_slide_refresh(C, pso);
1008
1009       /* clean up temp data */
1010       pose_slide_exit(op);
1011
1012       /* canceled! */
1013       return OPERATOR_CANCELLED;
1014     }
1015
1016     /* Percentage Chane... */
1017     case MOUSEMOVE: /* calculate new position */
1018     {
1019       /* only handle mousemove if not doing numinput */
1020       if (has_numinput == false) {
1021         /* update percentage based on position of mouse */
1022         pose_slide_mouse_update_percentage(pso, op, event);
1023
1024         /* update pose to reflect the new values (see below) */
1025         do_pose_update = true;
1026       }
1027       break;
1028     }
1029     default: {
1030       if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
1031         float value;
1032
1033         /* Grab percentage from numeric input, and store this new value for redo
1034          * NOTE: users see ints, while internally we use a 0-1 float
1035          */
1036         value = pso->percentage * 100.0f;
1037         applyNumInput(&pso->num, &value);
1038
1039         pso->percentage = value / 100.0f;
1040         CLAMP(pso->percentage, 0.0f, 1.0f);
1041         RNA_float_set(op->ptr, "percentage", pso->percentage);
1042
1043         /* Update pose to reflect the new values (see below) */
1044         do_pose_update = true;
1045         break;
1046       }
1047       else if (event->val == KM_PRESS) {
1048         switch (event->type) {
1049           /* Transform Channel Limits  */
1050           /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
1051           case GKEY: /* Location */
1052           {
1053             pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
1054             do_pose_update = true;
1055             break;
1056           }
1057           case RKEY: /* Rotation */
1058           {
1059             pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
1060             do_pose_update = true;
1061             break;
1062           }
1063           case SKEY: /* Scale */
1064           {
1065             pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
1066             do_pose_update = true;
1067             break;
1068           }
1069           case BKEY: /* Bendy Bones */
1070           {
1071             pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
1072             do_pose_update = true;
1073             break;
1074           }
1075           case CKEY: /* Custom Properties */
1076           {
1077             pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
1078             do_pose_update = true;
1079             break;
1080           }
1081
1082           /* Axis Locks */
1083           /* XXX: Hardcoded... */
1084           case XKEY: {
1085             if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
1086               do_pose_update = true;
1087             }
1088             break;
1089           }
1090           case YKEY: {
1091             if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
1092               do_pose_update = true;
1093             }
1094             break;
1095           }
1096           case ZKEY: {
1097             if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
1098               do_pose_update = true;
1099             }
1100             break;
1101           }
1102
1103           default: /* Some other unhandled key... */
1104             break;
1105         }
1106       }
1107       else {
1108         /* unhandled event - maybe it was some view manip? */
1109         /* allow to pass through */
1110         return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
1111       }
1112     }
1113   }
1114
1115   /* Perform pose updates - in response to some user action
1116    * (e.g. pressing a key or moving the mouse). */
1117   if (do_pose_update) {
1118     /* update percentage indicator in header */
1119     pose_slide_draw_status(pso);
1120
1121     /* reset transforms (to avoid accumulation errors) */
1122     pose_slide_reset(pso);
1123
1124     /* apply... */
1125     pose_slide_apply(C, pso);
1126   }
1127
1128   /* still running... */
1129   return OPERATOR_RUNNING_MODAL;
1130 }
1131
1132 /* common code for cancel() */
1133 static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op)
1134 {
1135   /* cleanup and done */
1136   pose_slide_exit(op);
1137 }
1138
1139 /* common code for exec() methods */
1140 static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
1141 {
1142   /* settings should have been set up ok for applying, so just apply! */
1143   pose_slide_apply(C, pso);
1144
1145   /* insert keyframes if needed */
1146   pose_slide_autoKeyframe(C, pso);
1147
1148   /* cleanup and done */
1149   pose_slide_exit(op);
1150
1151   return OPERATOR_FINISHED;
1152 }
1153
1154 /* common code for defining RNA properties */
1155 /* TODO: Skip save on these? */
1156 static void pose_slide_opdef_properties(wmOperatorType *ot)
1157 {
1158   RNA_def_float_percentage(ot->srna,
1159                            "percentage",
1160                            0.5f,
1161                            0.0f,
1162                            1.0f,
1163                            "Percentage",
1164                            "Weighting factor for which keyframe is favored more",
1165                            0.3,
1166                            0.7);
1167
1168   RNA_def_int(ot->srna,
1169               "prev_frame",
1170               0,
1171               MINAFRAME,
1172               MAXFRAME,
1173               "Previous Keyframe",
1174               "Frame number of keyframe immediately before the current frame",
1175               0,
1176               50);
1177   RNA_def_int(ot->srna,
1178               "next_frame",
1179               0,
1180               MINAFRAME,
1181               MAXFRAME,
1182               "Next Keyframe",
1183               "Frame number of keyframe immediately after the current frame",
1184               0,
1185               50);
1186
1187   RNA_def_enum(ot->srna,
1188                "channels",
1189                prop_channels_types,
1190                PS_TFM_ALL,
1191                "Channels",
1192                "Set of properties that are affected");
1193   RNA_def_enum(ot->srna,
1194                "axis_lock",
1195                prop_axis_lock_types,
1196                0,
1197                "Axis Lock",
1198                "Transform axis to restrict effects to");
1199 }
1200
1201 /* ------------------------------------ */
1202
1203 /* invoke() - for 'push' mode */
1204 static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1205 {
1206   tPoseSlideOp *pso;
1207
1208   /* initialize data  */
1209   if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
1210     pose_slide_exit(op);
1211     return OPERATOR_CANCELLED;
1212   }
1213   else {
1214     pso = op->customdata;
1215   }
1216
1217   /* initialise percentage so that it won't pop on first mouse move */
1218   pose_slide_mouse_update_percentage(pso, op, event);
1219
1220   /* do common setup work */
1221   return pose_slide_invoke_common(C, op, pso);
1222 }
1223
1224 /* exec() - for push */
1225 static int pose_slide_push_exec(bContext *C, wmOperator *op)
1226 {
1227   tPoseSlideOp *pso;
1228
1229   /* initialize data (from RNA-props) */
1230   if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
1231     pose_slide_exit(op);
1232     return OPERATOR_CANCELLED;
1233   }
1234   else {
1235     pso = op->customdata;
1236   }
1237
1238   /* do common exec work */
1239   return pose_slide_exec_common(C, op, pso);
1240 }
1241
1242 void POSE_OT_push(wmOperatorType *ot)
1243 {
1244   /* identifiers */
1245   ot->name = "Push Pose";
1246   ot->idname = "POSE_OT_push";
1247   ot->description = "Exaggerate the current pose";
1248
1249   /* callbacks */
1250   ot->exec = pose_slide_push_exec;
1251   ot->invoke = pose_slide_push_invoke;
1252   ot->modal = pose_slide_modal;
1253   ot->cancel = pose_slide_cancel;
1254   ot->poll = ED_operator_posemode;
1255
1256   /* flags */
1257   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1258
1259   /* Properties */
1260   pose_slide_opdef_properties(ot);
1261 }
1262
1263 /* ........................ */
1264
1265 /* invoke() - for 'relax' mode */
1266 static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1267 {
1268   tPoseSlideOp *pso;
1269
1270   /* initialize data  */
1271   if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
1272     pose_slide_exit(op);
1273     return OPERATOR_CANCELLED;
1274   }
1275   else {
1276     pso = op->customdata;
1277   }
1278
1279   /* initialise percentage so that it won't pop on first mouse move */
1280   pose_slide_mouse_update_percentage(pso, op, event);
1281
1282   /* do common setup work */
1283   return pose_slide_invoke_common(C, op, pso);
1284 }
1285
1286 /* exec() - for relax */
1287 static int pose_slide_relax_exec(bContext *C, wmOperator *op)
1288 {
1289   tPoseSlideOp *pso;
1290
1291   /* initialize data (from RNA-props) */
1292   if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
1293     pose_slide_exit(op);
1294     return OPERATOR_CANCELLED;
1295   }
1296   else {
1297     pso = op->customdata;
1298   }
1299
1300   /* do common exec work */
1301   return pose_slide_exec_common(C, op, pso);
1302 }
1303
1304 void POSE_OT_relax(wmOperatorType *ot)
1305 {
1306   /* identifiers */
1307   ot->name = "Relax Pose";
1308   ot->idname = "POSE_OT_relax";
1309   ot->description = "Make the current pose more similar to its surrounding ones";
1310
1311   /* callbacks */
1312   ot->exec = pose_slide_relax_exec;
1313   ot->invoke = pose_slide_relax_invoke;
1314   ot->modal = pose_slide_modal;
1315   ot->cancel = pose_slide_cancel;
1316   ot->poll = ED_operator_posemode;
1317
1318   /* flags */
1319   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1320
1321   /* Properties */
1322   pose_slide_opdef_properties(ot);
1323 }
1324
1325 /* ........................ */
1326
1327 /* invoke() - for 'breakdown' mode */
1328 static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1329 {
1330   tPoseSlideOp *pso;
1331
1332   /* initialize data  */
1333   if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
1334     pose_slide_exit(op);
1335     return OPERATOR_CANCELLED;
1336   }
1337   else {
1338     pso = op->customdata;
1339   }
1340
1341   /* initialise percentage so that it won't pop on first mouse move */
1342   pose_slide_mouse_update_percentage(pso, op, event);
1343
1344   /* do common setup work */
1345   return pose_slide_invoke_common(C, op, pso);
1346 }
1347
1348 /* exec() - for breakdown */
1349 static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
1350 {
1351   tPoseSlideOp *pso;
1352
1353   /* initialize data (from RNA-props) */
1354   if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
1355     pose_slide_exit(op);
1356     return OPERATOR_CANCELLED;
1357   }
1358   else {
1359     pso = op->customdata;
1360   }
1361
1362   /* do common exec work */
1363   return pose_slide_exec_common(C, op, pso);
1364 }
1365
1366 void POSE_OT_breakdown(wmOperatorType *ot)
1367 {
1368   /* identifiers */
1369   ot->name = "Pose Breakdowner";
1370   ot->idname = "POSE_OT_breakdown";
1371   ot->description = "Create a suitable breakdown pose on the current frame";
1372
1373   /* callbacks */
1374   ot->exec = pose_slide_breakdown_exec;
1375   ot->invoke = pose_slide_breakdown_invoke;
1376   ot->modal = pose_slide_modal;
1377   ot->cancel = pose_slide_cancel;
1378   ot->poll = ED_operator_posemode;
1379
1380   /* flags */
1381   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1382
1383   /* Properties */
1384   pose_slide_opdef_properties(ot);
1385 }
1386
1387 /* **************************************************** */
1388 /* B) Pose Propagate */
1389
1390 /* "termination conditions" - i.e. when we stop */
1391 typedef enum ePosePropagate_Termination {
1392   /* stop after the current hold ends */
1393   POSE_PROPAGATE_SMART_HOLDS = 0,
1394   /* only do on the last keyframe */
1395   POSE_PROPAGATE_LAST_KEY,
1396   /* stop after the next keyframe */
1397   POSE_PROPAGATE_NEXT_KEY,
1398   /* stop after the specified frame */
1399   POSE_PROPAGATE_BEFORE_FRAME,
1400   /* stop when we run out of keyframes */
1401   POSE_PROPAGATE_BEFORE_END,
1402
1403   /* only do on keyframes that are selected */
1404   POSE_PROPAGATE_SELECTED_KEYS,
1405   /* only do on the frames where markers are selected */
1406   POSE_PROPAGATE_SELECTED_MARKERS,
1407 } ePosePropagate_Termination;
1408
1409 /* Termination data needed for some modes -
1410  * assumes only one of these entries will be needed at a time. */
1411 typedef union tPosePropagate_ModeData {
1412   /* smart holds + before frame: frame number to stop on */
1413   float end_frame;
1414
1415   /* selected markers: listbase for CfraElem's marking these frames */
1416   ListBase sel_markers;
1417 } tPosePropagate_ModeData;
1418
1419 /* --------------------------------- */
1420
1421 /* get frame on which the "hold" for the bone ends
1422  * XXX: this may not really work that well if a bone moves on some channels and not others
1423  *      if this happens to be a major issue, scrap this, and just make this happen
1424  *      independently per F-Curve
1425  */
1426 static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float startFrame)
1427 {
1428   DLRBT_Tree keys;
1429
1430   Object *ob = pfl->ob;
1431   AnimData *adt = ob->adt;
1432   LinkData *ld;
1433   float endFrame = startFrame;
1434
1435   /* set up optimized data-structures for searching for relevant keyframes + holds */
1436   BLI_dlrbTree_init(&keys);
1437
1438   for (ld = pfl->fcurves.first; ld; ld = ld->next) {
1439     FCurve *fcu = (FCurve *)ld->data;
1440     fcurve_to_keylist(adt, fcu, &keys, 0);
1441   }
1442
1443   /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
1444    * - the best case would be one that starts on the frame itself
1445    */
1446   ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(
1447       &keys, compare_ak_cfraPtr, &startFrame);
1448
1449   /* There are only two cases for no-exact match:
1450    *  1) the current frame is just before another key but not on a key itself
1451    *  2) the current frame is on a key, but that key doesn't link to the next
1452    *
1453    * If we've got the first case, then we can search for another block,
1454    * otherwise forget it, as we'd be overwriting some valid data.
1455    */
1456   if (ab == NULL) {
1457     /* we've got case 1, so try the one after */
1458     ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
1459
1460     if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
1461       /* try the block before this frame then as last resort */
1462       ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
1463     }
1464   }
1465
1466   /* whatever happens, stop searching now... */
1467   if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
1468     /* restrict range to just the frame itself
1469      * i.e. everything is in motion, so no holds to safely overwrite
1470      */
1471     ab = NULL;
1472   }
1473
1474   /* check if we can go any further than we've already gone */
1475   if (ab) {
1476     /* go to next if it is also valid and meets "extension" criteria */
1477     while (ab->next) {
1478       ActKeyColumn *abn = ab->next;
1479
1480       /* must be valid */
1481       if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
1482         break;
1483       }
1484       /* should have the same number of curves */
1485       if (ab->totblock != abn->totblock) {
1486         break;
1487       }
1488
1489       /* we can extend the bounds to the end of this "next" block now */
1490       ab = abn;
1491     }
1492
1493     /* end frame can now take the value of the end of the block */
1494     endFrame = ab->next->cfra;
1495   }
1496
1497   /* free temp memory */
1498   BLI_dlrbTree_free(&keys);
1499
1500   /* return the end frame we've found */
1501   return endFrame;
1502 }
1503
1504 /* get reference value from F-Curve using RNA */
1505 static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value)
1506 {
1507   PointerRNA id_ptr, ptr;
1508   PropertyRNA *prop;
1509   bool found = false;
1510
1511   /* base pointer is always the object -> id_ptr */
1512   RNA_id_pointer_create(&ob->id, &id_ptr);
1513
1514   /* resolve the property... */
1515   if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
1516     if (RNA_property_array_check(prop)) {
1517       /* array */
1518       if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
1519         found = true;
1520         switch (RNA_property_type(prop)) {
1521           case PROP_BOOLEAN:
1522             *value = (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index);
1523             break;
1524           case PROP_INT:
1525             *value = (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index);
1526             break;
1527           case PROP_FLOAT:
1528             *value = RNA_property_float_get_index(&ptr, prop, fcu->array_index);
1529             break;
1530           default:
1531             found = false;
1532             break;
1533         }
1534       }
1535     }
1536     else {
1537       /* not an array */
1538       found = true;
1539       switch (RNA_property_type(prop)) {
1540         case PROP_BOOLEAN:
1541           *value = (float)RNA_property_boolean_get(&ptr, prop);
1542           break;
1543         case PROP_INT:
1544           *value = (float)RNA_property_int_get(&ptr, prop);
1545           break;
1546         case PROP_ENUM:
1547           *value = (float)RNA_property_enum_get(&ptr, prop);
1548           break;
1549         case PROP_FLOAT:
1550           *value = RNA_property_float_get(&ptr, prop);
1551           break;
1552         default:
1553           found = false;
1554           break;
1555       }
1556     }
1557   }
1558
1559   return found;
1560 }
1561
1562 /* propagate just works along each F-Curve in turn */
1563 static void pose_propagate_fcurve(
1564     wmOperator *op, Object *ob, FCurve *fcu, float startFrame, tPosePropagate_ModeData modeData)
1565 {
1566   const int mode = RNA_enum_get(op->ptr, "mode");
1567
1568   BezTriple *bezt;
1569   float refVal = 0.0f;
1570   bool keyExists;
1571   int i, match;
1572   short first = 1;
1573
1574   /* skip if no keyframes to edit */
1575   if ((fcu->bezt == NULL) || (fcu->totvert < 2)) {
1576     return;
1577   }
1578
1579   /* find the reference value from bones directly, which means that the user
1580    * doesn't need to firstly keyframe the pose (though this doesn't mean that
1581    * they can't either)
1582    */
1583   if (!pose_propagate_get_refVal(ob, fcu, &refVal)) {
1584     return;
1585   }
1586
1587   /* find the first keyframe to start propagating from
1588    * - if there's a keyframe on the current frame, we probably want to save this value there too
1589    *   since it may be as of yet unkeyed
1590    * - if starting before the starting frame, don't touch the key, as it may have had some valid
1591    *   values
1592    * - if only doing selected keyframes, start from the first one
1593    */
1594   if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
1595     match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
1596
1597     if (fcu->bezt[match].vec[1][0] < startFrame) {
1598       i = match + 1;
1599     }
1600     else {
1601       i = match;
1602     }
1603   }
1604   else {
1605     /* selected - start from first keyframe */
1606     i = 0;
1607   }
1608
1609   for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
1610     /* additional termination conditions based on the operator 'mode' property go here... */
1611     if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
1612       /* stop if keyframe is outside the accepted range */
1613       if (bezt->vec[1][0] > modeData.end_frame) {
1614         break;
1615       }
1616     }
1617     else if (mode == POSE_PROPAGATE_NEXT_KEY) {
1618       /* stop after the first keyframe has been processed */
1619       if (first == 0) {
1620         break;
1621       }
1622     }
1623     else if (mode == POSE_PROPAGATE_LAST_KEY) {
1624       /* only affect this frame if it will be the last one */
1625       if (i != (fcu->totvert - 1)) {
1626         continue;
1627       }
1628     }
1629     else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
1630       /* only allow if there's a marker on this frame */
1631       CfraElem *ce = NULL;
1632
1633       /* stop on matching marker if there is one */
1634       for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
1635         if (ce->cfra == round_fl_to_int(bezt->vec[1][0])) {
1636           break;
1637         }
1638       }
1639
1640       /* skip this keyframe if no marker */
1641       if (ce == NULL) {
1642         continue;
1643       }
1644     }
1645     else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
1646       /* only allow if this keyframe is already selected - skip otherwise */
1647       if (BEZT_ISSEL_ANY(bezt) == 0) {
1648         continue;
1649       }
1650     }
1651
1652     /* just flatten handles, since values will now be the same either side... */
1653     /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
1654     bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
1655
1656     /* select keyframe to indicate that it's been changed */
1657     bezt->f2 |= SELECT;
1658     first = 0;
1659   }
1660 }
1661
1662 /* --------------------------------- */
1663
1664 static int pose_propagate_exec(bContext *C, wmOperator *op)
1665 {
1666   Scene *scene = CTX_data_scene(C);
1667   ViewLayer *view_layer = CTX_data_view_layer(C);
1668   View3D *v3d = CTX_wm_view3d(C);
1669
1670   ListBase pflinks = {NULL, NULL};
1671   tPChanFCurveLink *pfl;
1672
1673   tPosePropagate_ModeData modeData;
1674   const int mode = RNA_enum_get(op->ptr, "mode");
1675
1676   /* isolate F-Curves related to the selected bones */
1677   poseAnim_mapping_get(C, &pflinks);
1678
1679   if (BLI_listbase_is_empty(&pflinks)) {
1680     /* There is a change the reason the list is empty is
1681      * that there is no valid object to propagate poses for.
1682      * This is very unlikely though, so we focus on the most likely issue. */
1683     BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
1684     return OPERATOR_CANCELLED;
1685   }
1686
1687   /* mode-specific data preprocessing (requiring no access to curves) */
1688   if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
1689     /* get a list of selected markers */
1690     ED_markers_make_cfra_list(&scene->markers, &modeData.sel_markers, SELECT);
1691   }
1692   else {
1693     /* assume everything else wants endFrame */
1694     modeData.end_frame = RNA_float_get(op->ptr, "end_frame");
1695   }
1696
1697   /* for each bone, perform the copying required */
1698   for (pfl = pflinks.first; pfl; pfl = pfl->next) {
1699     LinkData *ld;
1700
1701     /* mode-specific data preprocessing (requiring access to all curves) */
1702     if (mode == POSE_PROPAGATE_SMART_HOLDS) {
1703       /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
1704        * from the keyframe that occurs after the current frame
1705        */
1706       modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
1707     }
1708
1709     /* go through propagating pose to keyframes, curve by curve */
1710     for (ld = pfl->fcurves.first; ld; ld = ld->next) {
1711       pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
1712     }
1713   }
1714
1715   /* free temp data */
1716   poseAnim_mapping_free(&pflinks);
1717
1718   if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
1719     BLI_freelistN(&modeData.sel_markers);
1720   }
1721
1722   /* updates + notifiers */
1723   FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
1724     poseAnim_mapping_refresh(C, scene, ob);
1725   }
1726   FOREACH_OBJECT_IN_MODE_END;
1727
1728   return OPERATOR_FINISHED;
1729 }
1730
1731 /* --------------------------------- */
1732
1733 void POSE_OT_propagate(wmOperatorType *ot)
1734 {
1735   static const EnumPropertyItem terminate_items[] = {
1736       {POSE_PROPAGATE_SMART_HOLDS,
1737        "WHILE_HELD",
1738        0,
1739        "While Held",
1740        "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
1741       {POSE_PROPAGATE_NEXT_KEY,
1742        "NEXT_KEY",
1743        0,
1744        "To Next Keyframe",
1745        "Propagate pose to first keyframe following the current frame only"},
1746       {POSE_PROPAGATE_LAST_KEY,
1747        "LAST_KEY",
1748        0,
1749        "To Last Keyframe",
1750        "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
1751       {POSE_PROPAGATE_BEFORE_FRAME,
1752        "BEFORE_FRAME",
1753        0,
1754        "Before Frame",
1755        "Propagate pose to all keyframes between current frame and 'Frame' property"},
1756       {POSE_PROPAGATE_BEFORE_END,
1757        "BEFORE_END",
1758        0,
1759        "Before Last Keyframe",
1760        "Propagate pose to all keyframes from current frame until no more are found"},
1761       {POSE_PROPAGATE_SELECTED_KEYS,
1762        "SELECTED_KEYS",
1763        0,
1764        "On Selected Keyframes",
1765        "Propagate pose to all selected keyframes"},
1766       {POSE_PROPAGATE_SELECTED_MARKERS,
1767        "SELECTED_MARKERS",
1768        0,
1769        "On Selected Markers",
1770        "Propagate pose to all keyframes occurring on frames with Scene Markers after the current "
1771        "frame"},
1772       {0, NULL, 0, NULL, NULL},
1773   };
1774
1775   /* identifiers */
1776   ot->name = "Propagate Pose";
1777   ot->idname = "POSE_OT_propagate";
1778   ot->description =
1779       "Copy selected aspects of the current pose to subsequent poses already keyframed";
1780
1781   /* callbacks */
1782   ot->exec = pose_propagate_exec;
1783   ot->poll = ED_operator_posemode; /* XXX: needs selected bones! */
1784
1785   /* flag */
1786   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1787
1788   /* properties */
1789   /* TODO: add "fade out" control for tapering off amount of propagation as time goes by? */
1790   ot->prop = RNA_def_enum(ot->srna,
1791                           "mode",
1792                           terminate_items,
1793                           POSE_PROPAGATE_SMART_HOLDS,
1794                           "Terminate Mode",
1795                           "Method used to determine when to stop propagating pose to keyframes");
1796   RNA_def_float(ot->srna,
1797                 "end_frame",
1798                 250.0,
1799                 FLT_MIN,
1800                 FLT_MAX,
1801                 "End Frame",
1802                 "Frame to stop propagating frames to (for 'Before Frame' mode)",
1803                 1.0,
1804                 250.0);
1805 }
1806
1807 /* **************************************************** */