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) 2008 Blender Foundation
17 */
18
19 /** \file
20 * \ingroup edanimation
21 */
22
23 #include <float.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_blenlib.h"
31 #include "BLI_lasso_2d.h"
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34
35 #include "DNA_anim_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "BKE_fcurve.h"
40 #include "BKE_nla.h"
41
42 #include "ED_anim_api.h"
43 #include "ED_keyframes_edit.h"
44 #include "ED_markers.h"
45
46 /* This file defines an API and set of callback-operators for
47 * non-destructive editing of keyframe data.
48 *
49 * Two API functions are defined for actually performing the operations on the data:
50 * ANIM_fcurve_keyframes_loop()
51 * which take the data they operate on, a few callbacks defining what operations to perform.
52 *
53 * As operators which work on keyframes usually apply the same operation on all BezTriples in
54 * every channel, the code has been optimized providing a set of functions which will get the
55 * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
56 * to be called before getting any channels.
57 *
58 * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
59 * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which
60 * don't check existing selection status).
61 *
62 * - Joshua Leung, Dec 2008
63 */
64
65 /* ************************************************************************** */
66 /* Keyframe Editing Loops - Exposed API */
67
68 /* --------------------------- Base Functions ------------------------------------ */
69
70 /* This function is used to loop over BezTriples in the given F-Curve, applying a given
71 * operation on them, and optionally applies an F-Curve validation function afterwards.
72 */
73 /* TODO: make this function work on samples too. */
ANIM_fcurve_keyframes_loop(KeyframeEditData * ked,FCurve * fcu,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)74 short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
75 FCurve *fcu,
76 KeyframeEditFunc key_ok,
77 KeyframeEditFunc key_cb,
78 FcuEditFunc fcu_cb)
79 {
80 BezTriple *bezt;
81 short ok = 0;
82 uint i;
83
84 /* sanity check */
85 if (ELEM(NULL, fcu, fcu->bezt)) {
86 return 0;
87 }
88
89 /* set the F-Curve into the editdata so that it can be accessed */
90 if (ked) {
91 ked->fcu = fcu;
92 ked->curIndex = 0;
93 ked->curflags = ok;
94 }
95
96 /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
97 if (key_cb) {
98 /* if there's a validation func, include that check in the loop
99 * (this is should be more efficient than checking for it in every loop)
100 */
101 if (key_ok) {
102 for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
103 if (ked) {
104 /* advance the index, and reset the ok flags (to not influence the result) */
105 ked->curIndex = i;
106 ked->curflags = 0;
107 }
108
109 /* Only operate on this BezTriple if it fulfills the criteria of the validation func */
110 if ((ok = key_ok(ked, bezt))) {
111 if (ked) {
112 ked->curflags = ok;
113 }
114
115 /* Exit with return-code '1' if function returns positive
116 * This is useful if finding if some BezTriple satisfies a condition.
117 */
118 if (key_cb(ked, bezt)) {
119 return 1;
120 }
121 }
122 }
123 }
124 else {
125 for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
126 if (ked) {
127 ked->curIndex = i;
128 }
129
130 /* Exit with return-code '1' if function returns positive
131 * This is useful if finding if some BezTriple satisfies a condition.
132 */
133 if (key_cb(ked, bezt)) {
134 return 1;
135 }
136 }
137 }
138 }
139
140 /* unset the F-Curve from the editdata now that it's done */
141 if (ked) {
142 ked->fcu = NULL;
143 ked->curIndex = 0;
144 ked->curflags = 0;
145 }
146
147 /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
148 if (fcu_cb) {
149 fcu_cb(fcu);
150 }
151
152 /* done */
153 return 0;
154 }
155
156 /* --------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
157
158 /* This function is used to loop over the keyframe data in an Action Group */
agrp_keyframes_loop(KeyframeEditData * ked,bActionGroup * agrp,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)159 static short agrp_keyframes_loop(KeyframeEditData *ked,
160 bActionGroup *agrp,
161 KeyframeEditFunc key_ok,
162 KeyframeEditFunc key_cb,
163 FcuEditFunc fcu_cb)
164 {
165 FCurve *fcu;
166
167 /* sanity check */
168 if (agrp == NULL) {
169 return 0;
170 }
171
172 /* only iterate over the F-Curves that are in this group */
173 for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
174 if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) {
175 return 1;
176 }
177 }
178
179 return 0;
180 }
181
182 /* This function is used to loop over the keyframe data in an Action */
act_keyframes_loop(KeyframeEditData * ked,bAction * act,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)183 static short act_keyframes_loop(KeyframeEditData *ked,
184 bAction *act,
185 KeyframeEditFunc key_ok,
186 KeyframeEditFunc key_cb,
187 FcuEditFunc fcu_cb)
188 {
189 FCurve *fcu;
190
191 /* sanity check */
192 if (act == NULL) {
193 return 0;
194 }
195
196 /* just loop through all F-Curves */
197 for (fcu = act->curves.first; fcu; fcu = fcu->next) {
198 if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) {
199 return 1;
200 }
201 }
202
203 return 0;
204 }
205
206 /* This function is used to loop over the keyframe data in an Object */
ob_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,Object * ob,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)207 static short ob_keyframes_loop(KeyframeEditData *ked,
208 bDopeSheet *ads,
209 Object *ob,
210 KeyframeEditFunc key_ok,
211 KeyframeEditFunc key_cb,
212 FcuEditFunc fcu_cb)
213 {
214 bAnimContext ac = {NULL};
215 ListBase anim_data = {NULL, NULL};
216 bAnimListElem *ale;
217 int filter;
218 int ret = 0;
219
220 bAnimListElem dummychan = {NULL};
221 Base dummybase = {NULL};
222
223 if (ob == NULL) {
224 return 0;
225 }
226
227 /* create a dummy wrapper data to work with */
228 dummybase.object = ob;
229
230 dummychan.type = ANIMTYPE_OBJECT;
231 dummychan.data = &dummybase;
232 dummychan.id = &ob->id;
233 dummychan.adt = ob->adt;
234
235 ac.ads = ads;
236 ac.data = &dummychan;
237 ac.datatype = ANIMCONT_CHANNEL;
238
239 /* get F-Curves to take keyframes from */
240 filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
241 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
242
243 /* Loop through each F-Curve, applying the operation as required,
244 * but stopping on the first one. */
245 for (ale = anim_data.first; ale; ale = ale->next) {
246 if (ANIM_fcurve_keyframes_loop(ked, (FCurve *)ale->data, key_ok, key_cb, fcu_cb)) {
247 ret = 1;
248 break;
249 }
250 }
251
252 ANIM_animdata_freelist(&anim_data);
253
254 /* return return code - defaults to zero if nothing happened */
255 return ret;
256 }
257
258 /* This function is used to loop over the keyframe data in a Scene */
scene_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,Scene * sce,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)259 static short scene_keyframes_loop(KeyframeEditData *ked,
260 bDopeSheet *ads,
261 Scene *sce,
262 KeyframeEditFunc key_ok,
263 KeyframeEditFunc key_cb,
264 FcuEditFunc fcu_cb)
265 {
266 bAnimContext ac = {NULL};
267 ListBase anim_data = {NULL, NULL};
268 bAnimListElem *ale;
269 int filter;
270 int ret = 0;
271
272 bAnimListElem dummychan = {NULL};
273
274 if (sce == NULL) {
275 return 0;
276 }
277
278 /* create a dummy wrapper data to work with */
279 dummychan.type = ANIMTYPE_SCENE;
280 dummychan.data = sce;
281 dummychan.id = &sce->id;
282 dummychan.adt = sce->adt;
283
284 ac.ads = ads;
285 ac.data = &dummychan;
286 ac.datatype = ANIMCONT_CHANNEL;
287
288 /* get F-Curves to take keyframes from */
289 filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
290 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
291
292 /* Loop through each F-Curve, applying the operation as required,
293 * but stopping on the first one. */
294 for (ale = anim_data.first; ale; ale = ale->next) {
295 if (ANIM_fcurve_keyframes_loop(ked, (FCurve *)ale->data, key_ok, key_cb, fcu_cb)) {
296 ret = 1;
297 break;
298 }
299 }
300
301 ANIM_animdata_freelist(&anim_data);
302
303 /* return return code - defaults to zero if nothing happened */
304 return ret;
305 }
306
307 /* This function is used to loop over the keyframe data in a DopeSheet summary */
summary_keyframes_loop(KeyframeEditData * ked,bAnimContext * ac,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)308 static short summary_keyframes_loop(KeyframeEditData *ked,
309 bAnimContext *ac,
310 KeyframeEditFunc key_ok,
311 KeyframeEditFunc key_cb,
312 FcuEditFunc fcu_cb)
313 {
314 ListBase anim_data = {NULL, NULL};
315 bAnimListElem *ale;
316 int filter, ret_code = 0;
317
318 /* sanity check */
319 if (ac == NULL) {
320 return 0;
321 }
322
323 /* get F-Curves to take keyframes from */
324 filter = ANIMFILTER_DATA_VISIBLE;
325 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
326
327 /* loop through each F-Curve, working on the keyframes until the first curve aborts */
328 for (ale = anim_data.first; ale; ale = ale->next) {
329 switch (ale->datatype) {
330 case ALE_MASKLAY:
331 case ALE_GPFRAME:
332 break;
333
334 case ALE_FCURVE:
335 default: {
336 if (ked && ked->iterflags) {
337 /* make backups of the current values, so that a localized fix
338 * (e.g. NLA time remapping) can be applied to these values
339 */
340 float f1 = ked->f1;
341 float f2 = ked->f2;
342
343 if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
344 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
345
346 if (ked->iterflags & KED_F1_NLA_UNMAP) {
347 ked->f1 = BKE_nla_tweakedit_remap(adt, f1, NLATIME_CONVERT_UNMAP);
348 }
349 if (ked->iterflags & KED_F2_NLA_UNMAP) {
350 ked->f2 = BKE_nla_tweakedit_remap(adt, f2, NLATIME_CONVERT_UNMAP);
351 }
352 }
353
354 /* now operate on the channel as per normal */
355 ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
356
357 /* reset */
358 ked->f1 = f1;
359 ked->f2 = f2;
360 }
361 else {
362 /* no special handling required... */
363 ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
364 }
365 break;
366 }
367 }
368
369 if (ret_code) {
370 break;
371 }
372 }
373
374 ANIM_animdata_freelist(&anim_data);
375
376 return ret_code;
377 }
378
379 /* --- */
380
381 /* This function is used to apply operation to all keyframes, regardless of the type */
ANIM_animchannel_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,bAnimListElem * ale,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)382 short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
383 bDopeSheet *ads,
384 bAnimListElem *ale,
385 KeyframeEditFunc key_ok,
386 KeyframeEditFunc key_cb,
387 FcuEditFunc fcu_cb)
388 {
389 /* sanity checks */
390 if (ale == NULL) {
391 return 0;
392 }
393
394 /* method to use depends on the type of keyframe data */
395 switch (ale->datatype) {
396 /* direct keyframe data (these loops are exposed) */
397 case ALE_FCURVE: /* F-Curve */
398 return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb);
399
400 /* indirect 'summaries' (these are not exposed directly)
401 * NOTE: must keep this code in sync with the drawing code and also the filtering code!
402 */
403 case ALE_GROUP: /* action group */
404 return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb);
405 case ALE_ACT: /* action */
406 return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb);
407
408 case ALE_OB: /* object */
409 return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb);
410 case ALE_SCE: /* scene */
411 return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb);
412 case ALE_ALL: /* 'all' (DopeSheet summary) */
413 return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb);
414 }
415
416 return 0;
417 }
418
419 /* This function is used to apply operation to all keyframes,
420 * regardless of the type without needed an AnimListElem wrapper */
ANIM_animchanneldata_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,void * data,int keytype,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)421 short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
422 bDopeSheet *ads,
423 void *data,
424 int keytype,
425 KeyframeEditFunc key_ok,
426 KeyframeEditFunc key_cb,
427 FcuEditFunc fcu_cb)
428 {
429 /* sanity checks */
430 if (data == NULL) {
431 return 0;
432 }
433
434 /* method to use depends on the type of keyframe data */
435 switch (keytype) {
436 /* direct keyframe data (these loops are exposed) */
437 case ALE_FCURVE: /* F-Curve */
438 return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb);
439
440 /* indirect 'summaries' (these are not exposed directly)
441 * NOTE: must keep this code in sync with the drawing code and also the filtering code!
442 */
443 case ALE_GROUP: /* action group */
444 return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb);
445 case ALE_ACT: /* action */
446 return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb);
447
448 case ALE_OB: /* object */
449 return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb);
450 case ALE_SCE: /* scene */
451 return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb);
452 case ALE_ALL: /* 'all' (DopeSheet summary) */
453 return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb);
454 }
455
456 return 0;
457 }
458
ANIM_animdata_keyframe_callback(bAnimContext * ac,eAnimFilter_Flags filter,KeyframeEditFunc callback_fn)459 void ANIM_animdata_keyframe_callback(bAnimContext *ac,
460 eAnimFilter_Flags filter,
461 KeyframeEditFunc callback_fn)
462 {
463 ListBase anim_data = {NULL, NULL};
464 bAnimListElem *ale;
465
466 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
467
468 for (ale = anim_data.first; ale; ale = ale->next) {
469 ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, callback_fn, calchandles_fcurve);
470 ale->update |= ANIM_UPDATE_DEFAULT;
471 }
472
473 ANIM_animdata_update(ac, &anim_data);
474 ANIM_animdata_freelist(&anim_data);
475 }
476
477 /* ************************************************************************** */
478 /* Keyframe Integrity Tools */
479
480 /* Rearrange keyframes if some are out of order */
481 /* used to be recalc_*_ipos() where * was object or action */
ANIM_editkeyframes_refresh(bAnimContext * ac)482 void ANIM_editkeyframes_refresh(bAnimContext *ac)
483 {
484 ListBase anim_data = {NULL, NULL};
485 bAnimListElem *ale;
486 int filter;
487
488 /* filter animation data */
489 filter = ANIMFILTER_DATA_VISIBLE;
490 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
491
492 /* Loop over F-Curves that are likely to have been edited, and tag them to
493 * ensure the keyframes are in order and handles are in a valid position. */
494 for (ale = anim_data.first; ale; ale = ale->next) {
495 ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER;
496 }
497
498 /* free temp data */
499 ANIM_animdata_update(ac, &anim_data);
500 ANIM_animdata_freelist(&anim_data);
501 }
502
503 /* ************************************************************************** */
504 /* BezTriple Validation Callbacks */
505
506 /* ------------------------ */
507 /* Some macros to make this easier... */
508
509 /* run the given check on the 3 handles:
510 * - Check should be a macro, which takes the handle index as its single arg,
511 * which it substitutes later.
512 * - Requires that a var, of type short, is named 'ok',
513 * and has been initialized to 0.
514 */
515 #define KEYFRAME_OK_CHECKS(check) \
516 { \
517 CHECK_TYPE(ok, short); \
518 if (check(1)) { \
519 ok |= KEYFRAME_OK_KEY; \
520 } \
521 if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
522 /* Only act on visible items, so check handle visibility state. */ \
523 const bool handles_visible = ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ? \
524 (BEZT_ISSEL_ANY(bezt)) : \
525 true); \
526 if (handles_visible) { \
527 if (check(0)) { \
528 ok |= KEYFRAME_OK_H1; \
529 } \
530 if (check(2)) { \
531 ok |= KEYFRAME_OK_H2; \
532 } \
533 } \
534 } \
535 } \
536 (void)0
537
538 /* ------------------------ */
539
ok_bezier_frame(KeyframeEditData * ked,BezTriple * bezt)540 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
541 {
542 short ok = 0;
543
544 /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
545 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
546 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
547 #undef KEY_CHECK_OK
548
549 /* return ok flags */
550 return ok;
551 }
552
ok_bezier_framerange(KeyframeEditData * ked,BezTriple * bezt)553 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
554 {
555 short ok = 0;
556
557 /* frame range is stored in float properties */
558 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
559 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
560 #undef KEY_CHECK_OK
561
562 /* return ok flags */
563 return ok;
564 }
565
ok_bezier_selected(KeyframeEditData * UNUSED (ked),BezTriple * bezt)566 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
567 {
568 /* this macro checks all beztriple handles for selection...
569 * only one of the verts has to be selected for this to be ok...
570 */
571 if (BEZT_ISSEL_ANY(bezt)) {
572 return KEYFRAME_OK_ALL;
573 }
574 return 0;
575 }
576
ok_bezier_value(KeyframeEditData * ked,BezTriple * bezt)577 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
578 {
579 short ok = 0;
580
581 /* Value is stored in f1 property:
582 * - This float accuracy check may need to be dropped?
583 * - Should value be stored in f2 instead
584 * so that we won't have conflicts when using f1 for frames too?
585 */
586 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
587 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
588 #undef KEY_CHECK_OK
589
590 /* return ok flags */
591 return ok;
592 }
593
ok_bezier_valuerange(KeyframeEditData * ked,BezTriple * bezt)594 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
595 {
596 short ok = 0;
597
598 /* value range is stored in float properties */
599 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
600 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
601 #undef KEY_CHECK_OK
602
603 /* return ok flags */
604 return ok;
605 }
606
ok_bezier_region(KeyframeEditData * ked,BezTriple * bezt)607 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
608 {
609 /* rect is stored in data property (it's of type rectf, but may not be set) */
610 if (ked->data) {
611 short ok = 0;
612
613 #define KEY_CHECK_OK(_index) BLI_rctf_isect_pt_v(ked->data, bezt->vec[_index])
614 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
615 #undef KEY_CHECK_OK
616
617 /* return ok flags */
618 return ok;
619 }
620 return 0;
621 }
622
623 /**
624 * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
625 */
keyframe_region_lasso_test(const KeyframeEdit_LassoData * data_lasso,const float xy[2])626 bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
627 {
628 if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
629 float xy_view[2];
630
631 BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
632
633 if (BLI_lasso_is_point_inside(
634 data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) {
635 return true;
636 }
637 }
638
639 return false;
640 }
641
ok_bezier_region_lasso(KeyframeEditData * ked,BezTriple * bezt)642 static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
643 {
644 /* check for lasso customdata (KeyframeEdit_LassoData) */
645 if (ked->data) {
646 short ok = 0;
647
648 #define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
649 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
650 #undef KEY_CHECK_OK
651
652 /* return ok flags */
653 return ok;
654 }
655 return 0;
656 }
657
ok_bezier_channel_lasso(KeyframeEditData * ked,BezTriple * bezt)658 static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
659 {
660 /* check for lasso customdata (KeyframeEdit_LassoData) */
661 if (ked->data) {
662 KeyframeEdit_LassoData *data = ked->data;
663 float pt[2];
664
665 /* late-binding remap of the x values (for summary channels) */
666 /* XXX: Ideally we reset, but it should be fine just leaving it as-is
667 * as the next channel will reset it properly, while the next summary-channel
668 * curve will also reset by itself...
669 */
670 if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
671 data->rectf_scaled->xmin = ked->f1;
672 data->rectf_scaled->xmax = ked->f2;
673 }
674
675 /* only use the x-coordinate of the point; the y is the channel range... */
676 pt[0] = bezt->vec[1][0];
677 pt[1] = ked->channel_y;
678
679 if (keyframe_region_lasso_test(data, pt)) {
680 return KEYFRAME_OK_KEY;
681 }
682 }
683 return 0;
684 }
685
686 /**
687 * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
688 */
keyframe_region_circle_test(const KeyframeEdit_CircleData * data_circle,const float xy[2])689 bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
690 {
691 if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
692 float xy_view[2];
693
694 BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy);
695
696 xy_view[0] = xy_view[0] - data_circle->mval[0];
697 xy_view[1] = xy_view[1] - data_circle->mval[1];
698 return len_squared_v2(xy_view) < data_circle->radius_squared;
699 }
700
701 return false;
702 }
703
ok_bezier_region_circle(KeyframeEditData * ked,BezTriple * bezt)704 static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
705 {
706 /* check for circle select customdata (KeyframeEdit_CircleData) */
707 if (ked->data) {
708 short ok = 0;
709
710 #define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
711 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
712 #undef KEY_CHECK_OK
713
714 /* return ok flags */
715 return ok;
716 }
717 return 0;
718 }
719
ok_bezier_channel_circle(KeyframeEditData * ked,BezTriple * bezt)720 static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
721 {
722 /* check for circle select customdata (KeyframeEdit_CircleData) */
723 if (ked->data) {
724 KeyframeEdit_CircleData *data = ked->data;
725 float pt[2];
726
727 /* late-binding remap of the x values (for summary channels) */
728 /* XXX: Ideally we reset, but it should be fine just leaving it as-is
729 * as the next channel will reset it properly, while the next summary-channel
730 * curve will also reset by itself...
731 */
732 if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
733 data->rectf_scaled->xmin = ked->f1;
734 data->rectf_scaled->xmax = ked->f2;
735 }
736
737 /* only use the x-coordinate of the point; the y is the channel range... */
738 pt[0] = bezt->vec[1][0];
739 pt[1] = ked->channel_y;
740
741 if (keyframe_region_circle_test(data, pt)) {
742 return KEYFRAME_OK_KEY;
743 }
744 }
745 return 0;
746 }
747
ANIM_editkeyframes_ok(short mode)748 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
749 {
750 /* eEditKeyframes_Validate */
751 switch (mode) {
752 case BEZT_OK_FRAME:
753 /* only if bezt falls on the right frame (float) */
754 return ok_bezier_frame;
755 case BEZT_OK_FRAMERANGE:
756 /* only if bezt falls within the specified frame range (floats) */
757 return ok_bezier_framerange;
758 case BEZT_OK_SELECTED:
759 /* only if bezt is selected (self) */
760 return ok_bezier_selected;
761 case BEZT_OK_VALUE:
762 /* only if bezt value matches (float) */
763 return ok_bezier_value;
764 case BEZT_OK_VALUERANGE:
765 /* only if bezier falls within the specified value range (floats) */
766 return ok_bezier_valuerange;
767 case BEZT_OK_REGION:
768 /* only if bezier falls within the specified rect (data -> rectf) */
769 return ok_bezier_region;
770 case BEZT_OK_REGION_LASSO:
771 /* only if the point falls within KeyframeEdit_LassoData defined data */
772 return ok_bezier_region_lasso;
773 case BEZT_OK_REGION_CIRCLE:
774 /* only if the point falls within KeyframeEdit_CircleData defined data */
775 return ok_bezier_region_circle;
776 case BEZT_OK_CHANNEL_LASSO:
777 /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
778 return ok_bezier_channel_lasso;
779 case BEZT_OK_CHANNEL_CIRCLE:
780 /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
781 return ok_bezier_channel_circle;
782 default: /* nothing was ok */
783 return NULL;
784 }
785 }
786
787 /* ******************************************* */
788 /* Assorted Utility Functions */
789
790 /**
791 * Helper callback for <animeditor>_cfrasnap_exec() ->
792 * used to help get the average time of all selected beztriples
793 */
bezt_calc_average(KeyframeEditData * ked,BezTriple * bezt)794 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
795 {
796 /* only if selected */
797 if (bezt->f2 & SELECT) {
798 /* store average time in float 1 (only do rounding at last step) */
799 ked->f1 += bezt->vec[1][0];
800
801 /* store average value in float 2 (only do rounding at last step)
802 * - this isn't always needed, but some operators may also require this
803 */
804 ked->f2 += bezt->vec[1][1];
805
806 /* increment number of items */
807 ked->i1++;
808 }
809
810 return 0;
811 }
812
813 /* helper callback for columnselect_<animeditor>_keys() -> populate
814 * list CfraElems with frame numbers from selected beztriples */
bezt_to_cfraelem(KeyframeEditData * ked,BezTriple * bezt)815 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
816 {
817 /* only if selected */
818 if (bezt->f2 & SELECT) {
819 CfraElem *ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
820 BLI_addtail(&ked->list, ce);
821
822 ce->cfra = bezt->vec[1][0];
823 }
824
825 return 0;
826 }
827
828 /* used to remap times from one range to another
829 * requires: ked->data = KeyframeEditCD_Remap
830 */
bezt_remap_times(KeyframeEditData * ked,BezTriple * bezt)831 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
832 {
833 KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
834 const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
835
836 /* perform transform on all three handles unless indicated otherwise */
837 /* TODO: need to include some checks for that */
838
839 bezt->vec[0][0] = scale * (bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
840 bezt->vec[1][0] = scale * (bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
841 bezt->vec[2][0] = scale * (bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
842 }
843
844 /* ******************************************* */
845 /* Transform */
846
847 /* snaps the keyframe to the nearest frame */
snap_bezier_nearest(KeyframeEditData * UNUSED (ked),BezTriple * bezt)848 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
849 {
850 if (bezt->f2 & SELECT) {
851 bezt->vec[1][0] = (float)(floorf(bezt->vec[1][0] + 0.5f));
852 }
853 return 0;
854 }
855
856 /* snaps the keyframe to the nearest second */
snap_bezier_nearestsec(KeyframeEditData * ked,BezTriple * bezt)857 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
858 {
859 const Scene *scene = ked->scene;
860 const float secf = (float)FPS;
861
862 if (bezt->f2 & SELECT) {
863 bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf);
864 }
865 return 0;
866 }
867
868 /* snaps the keyframe to the current frame */
snap_bezier_cframe(KeyframeEditData * ked,BezTriple * bezt)869 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
870 {
871 const Scene *scene = ked->scene;
872 if (bezt->f2 & SELECT) {
873 bezt->vec[1][0] = (float)CFRA;
874 }
875 return 0;
876 }
877
878 /* snaps the keyframe time to the nearest marker's frame */
snap_bezier_nearmarker(KeyframeEditData * ked,BezTriple * bezt)879 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
880 {
881 if (bezt->f2 & SELECT) {
882 bezt->vec[1][0] = (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
883 }
884 return 0;
885 }
886
887 /* make the handles have the same value as the key */
snap_bezier_horizontal(KeyframeEditData * UNUSED (ked),BezTriple * bezt)888 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
889 {
890 if (bezt->f2 & SELECT) {
891 bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
892
893 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
894 bezt->h1 = HD_ALIGN;
895 }
896 if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
897 bezt->h2 = HD_ALIGN;
898 }
899 }
900 return 0;
901 }
902
903 /* frame to snap to is stored in the custom data -> first float value slot */
snap_bezier_time(KeyframeEditData * ked,BezTriple * bezt)904 static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
905 {
906 if (bezt->f2 & SELECT) {
907 bezt->vec[1][0] = ked->f1;
908 }
909 return 0;
910 }
911
912 /* value to snap to is stored in the custom data -> first float value slot */
snap_bezier_value(KeyframeEditData * ked,BezTriple * bezt)913 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
914 {
915 if (bezt->f2 & SELECT) {
916 bezt->vec[1][1] = ked->f1;
917 }
918 return 0;
919 }
920
ANIM_editkeyframes_snap(short mode)921 KeyframeEditFunc ANIM_editkeyframes_snap(short mode)
922 {
923 /* eEditKeyframes_Snap */
924 switch (mode) {
925 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
926 return snap_bezier_nearest;
927 case SNAP_KEYS_CURFRAME: /* snap to current frame */
928 return snap_bezier_cframe;
929 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
930 return snap_bezier_nearmarker;
931 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
932 return snap_bezier_nearestsec;
933 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
934 return snap_bezier_horizontal;
935 case SNAP_KEYS_TIME: /* snap to given frame/time */
936 return snap_bezier_time;
937 case SNAP_KEYS_VALUE: /* snap to given value */
938 return snap_bezier_value;
939 default: /* just in case */
940 return snap_bezier_nearest;
941 }
942 }
943
944 /* --------- */
945
mirror_bezier_xaxis_ex(BezTriple * bezt,const float center)946 static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center)
947 {
948 for (int i = 0; i < 3; i++) {
949 float diff = (center - bezt->vec[i][0]);
950 bezt->vec[i][0] = (center + diff);
951 }
952 swap_v3_v3(bezt->vec[0], bezt->vec[2]);
953
954 SWAP(uint8_t, bezt->h1, bezt->h2);
955 SWAP(uint8_t, bezt->f1, bezt->f3);
956 }
957
mirror_bezier_yaxis_ex(BezTriple * bezt,const float center)958 static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center)
959 {
960 for (int i = 0; i < 3; i++) {
961 float diff = (center - bezt->vec[i][1]);
962 bezt->vec[i][1] = (center + diff);
963 }
964 }
965
mirror_bezier_cframe(KeyframeEditData * ked,BezTriple * bezt)966 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
967 {
968 const Scene *scene = ked->scene;
969
970 if (bezt->f2 & SELECT) {
971 mirror_bezier_xaxis_ex(bezt, CFRA);
972 }
973
974 return 0;
975 }
976
mirror_bezier_yaxis(KeyframeEditData * UNUSED (ked),BezTriple * bezt)977 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
978 {
979 if (bezt->f2 & SELECT) {
980 /* Yes, names are inverted, we are mirroring across y axis, hence along x axis... */
981 mirror_bezier_xaxis_ex(bezt, 0.0f);
982 }
983
984 return 0;
985 }
986
mirror_bezier_xaxis(KeyframeEditData * UNUSED (ked),BezTriple * bezt)987 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
988 {
989 if (bezt->f2 & SELECT) {
990 /* Yes, names are inverted, we are mirroring across x axis, hence along y axis... */
991 mirror_bezier_yaxis_ex(bezt, 0.0f);
992 }
993
994 return 0;
995 }
996
mirror_bezier_marker(KeyframeEditData * ked,BezTriple * bezt)997 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
998 {
999 /* mirroring time stored in f1 */
1000 if (bezt->f2 & SELECT) {
1001 mirror_bezier_xaxis_ex(bezt, ked->f1);
1002 }
1003
1004 return 0;
1005 }
1006
mirror_bezier_time(KeyframeEditData * ked,BezTriple * bezt)1007 static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
1008 {
1009 /* value to mirror over is stored in f1 */
1010 if (bezt->f2 & SELECT) {
1011 mirror_bezier_xaxis_ex(bezt, ked->f1);
1012 }
1013
1014 return 0;
1015 }
1016
mirror_bezier_value(KeyframeEditData * ked,BezTriple * bezt)1017 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
1018 {
1019 /* value to mirror over is stored in the custom data -> first float value slot */
1020 if (bezt->f2 & SELECT) {
1021 mirror_bezier_yaxis_ex(bezt, ked->f1);
1022 }
1023
1024 return 0;
1025 }
1026
1027 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
1028 /* calchandles_fcurve */
ANIM_editkeyframes_mirror(short mode)1029 KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
1030 {
1031 switch (mode) {
1032 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
1033 return mirror_bezier_cframe;
1034 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
1035 return mirror_bezier_yaxis;
1036 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
1037 return mirror_bezier_xaxis;
1038 case MIRROR_KEYS_MARKER: /* mirror over marker */
1039 return mirror_bezier_marker;
1040 case MIRROR_KEYS_TIME: /* mirror over frame/time */
1041 return mirror_bezier_time;
1042 case MIRROR_KEYS_VALUE: /* mirror over given value */
1043 return mirror_bezier_value;
1044 default: /* just in case */
1045 return mirror_bezier_yaxis;
1046 }
1047 }
1048
1049 /* ******************************************* */
1050 /* Settings */
1051
1052 /**
1053 * Standard validation step for a few of these
1054 * (implemented as macro for inlining without fn-call overhead):
1055 * "if the handles are not of the same type, set them to type free".
1056 */
1057 #define ENSURE_HANDLES_MATCH(bezt) \
1058 if (bezt->h1 != bezt->h2) { \
1059 if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) { \
1060 bezt->h1 = HD_FREE; \
1061 } \
1062 if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) { \
1063 bezt->h2 = HD_FREE; \
1064 } \
1065 } \
1066 (void)0
1067
1068 /* Sets the selected bezier handles to type 'auto' */
set_bezier_auto(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1069 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1070 {
1071 /* If the key is selected, always apply to both handles. */
1072 if (bezt->f2 & SELECT) {
1073 bezt->h1 = bezt->h2 = HD_AUTO;
1074 }
1075 else {
1076 if (bezt->f1 & SELECT) {
1077 bezt->h1 = HD_AUTO;
1078 }
1079 if (bezt->f3 & SELECT) {
1080 bezt->h2 = HD_AUTO;
1081 }
1082
1083 ENSURE_HANDLES_MATCH(bezt);
1084 }
1085
1086 return 0;
1087 }
1088
1089 /* Sets the selected bezier handles to type 'auto-clamped'
1090 * NOTE: this is like auto above, but they're handled a bit different
1091 */
set_bezier_auto_clamped(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1092 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1093 {
1094 /* If the key is selected, always apply to both handles. */
1095 if (bezt->f2 & SELECT) {
1096 bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
1097 }
1098 else {
1099 if (bezt->f1 & SELECT) {
1100 bezt->h1 = HD_AUTO_ANIM;
1101 }
1102 if (bezt->f3 & SELECT) {
1103 bezt->h2 = HD_AUTO_ANIM;
1104 }
1105
1106 ENSURE_HANDLES_MATCH(bezt);
1107 }
1108
1109 return 0;
1110 }
1111
1112 /* Sets the selected bezier handles to type 'vector' */
set_bezier_vector(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1113 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1114 {
1115 /* If the key is selected, always apply to both handles. */
1116 if (bezt->f2 & SELECT) {
1117 bezt->h1 = bezt->h2 = HD_VECT;
1118 }
1119 else {
1120 if (bezt->f1 & SELECT) {
1121 bezt->h1 = HD_VECT;
1122 }
1123 if (bezt->f3 & SELECT) {
1124 bezt->h2 = HD_VECT;
1125 }
1126 }
1127
1128 return 0;
1129 }
1130
1131 /**
1132 * Queries if the handle should be set to 'free' or 'align'.
1133 *
1134 * \note This was used for the 'toggle free/align' option
1135 * currently this isn't used, but may be restored later.
1136 */
bezier_isfree(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1137 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1138 {
1139 if ((bezt->f1 & SELECT) && (bezt->h1)) {
1140 return 1;
1141 }
1142 if ((bezt->f3 & SELECT) && (bezt->h2)) {
1143 return 1;
1144 }
1145 return 0;
1146 }
1147
1148 /* Sets selected bezier handles to type 'align' */
set_bezier_align(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1149 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1150 {
1151 /* If the key is selected, always apply to both handles. */
1152 if (bezt->f2 & SELECT) {
1153 bezt->h1 = bezt->h2 = HD_ALIGN;
1154 }
1155 else {
1156 if (bezt->f1 & SELECT) {
1157 bezt->h1 = HD_ALIGN;
1158 }
1159 if (bezt->f3 & SELECT) {
1160 bezt->h2 = HD_ALIGN;
1161 }
1162 }
1163
1164 return 0;
1165 }
1166
1167 /* Sets selected bezier handles to type 'free' */
set_bezier_free(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1168 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1169 {
1170 /* If the key is selected, always apply to both handles. */
1171 if (bezt->f2 & SELECT) {
1172 bezt->h1 = bezt->h2 = HD_FREE;
1173 }
1174 else {
1175 if (bezt->f1 & SELECT) {
1176 bezt->h1 = HD_FREE;
1177 }
1178 if (bezt->f3 & SELECT) {
1179 bezt->h2 = HD_FREE;
1180 }
1181 }
1182
1183 return 0;
1184 }
1185
1186 /* Set all selected Bezier Handles to a single type */
1187 /* calchandles_fcurve */
ANIM_editkeyframes_handles(short mode)1188 KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
1189 {
1190 switch (mode) {
1191 case HD_AUTO: /* auto */
1192 return set_bezier_auto;
1193 case HD_AUTO_ANIM: /* auto clamped */
1194 return set_bezier_auto_clamped;
1195
1196 case HD_VECT: /* vector */
1197 return set_bezier_vector;
1198 case HD_FREE: /* free */
1199 return set_bezier_free;
1200 case HD_ALIGN: /* align */
1201 return set_bezier_align;
1202
1203 default: /* check for toggle free or align? */
1204 return bezier_isfree;
1205 }
1206 }
1207
1208 /* ------- */
1209
set_bezt_constant(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1210 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1211 {
1212 if (bezt->f2 & SELECT) {
1213 bezt->ipo = BEZT_IPO_CONST;
1214 }
1215 return 0;
1216 }
1217
set_bezt_linear(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1218 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1219 {
1220 if (bezt->f2 & SELECT) {
1221 bezt->ipo = BEZT_IPO_LIN;
1222 }
1223 return 0;
1224 }
1225
set_bezt_bezier(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1226 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1227 {
1228 if (bezt->f2 & SELECT) {
1229 bezt->ipo = BEZT_IPO_BEZ;
1230 }
1231 return 0;
1232 }
1233
set_bezt_back(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1234 static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1235 {
1236 if (bezt->f2 & SELECT) {
1237 bezt->ipo = BEZT_IPO_BACK;
1238 }
1239 return 0;
1240 }
1241
set_bezt_bounce(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1242 static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1243 {
1244 if (bezt->f2 & SELECT) {
1245 bezt->ipo = BEZT_IPO_BOUNCE;
1246 }
1247 return 0;
1248 }
1249
set_bezt_circle(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1250 static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1251 {
1252 if (bezt->f2 & SELECT) {
1253 bezt->ipo = BEZT_IPO_CIRC;
1254 }
1255 return 0;
1256 }
1257
set_bezt_cubic(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1258 static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1259 {
1260 if (bezt->f2 & SELECT) {
1261 bezt->ipo = BEZT_IPO_CUBIC;
1262 }
1263 return 0;
1264 }
1265
set_bezt_elastic(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1266 static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1267 {
1268 if (bezt->f2 & SELECT) {
1269 bezt->ipo = BEZT_IPO_ELASTIC;
1270 }
1271 return 0;
1272 }
1273
set_bezt_expo(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1274 static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1275 {
1276 if (bezt->f2 & SELECT) {
1277 bezt->ipo = BEZT_IPO_EXPO;
1278 }
1279 return 0;
1280 }
1281
set_bezt_quad(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1282 static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1283 {
1284 if (bezt->f2 & SELECT) {
1285 bezt->ipo = BEZT_IPO_QUAD;
1286 }
1287 return 0;
1288 }
1289
set_bezt_quart(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1290 static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1291 {
1292 if (bezt->f2 & SELECT) {
1293 bezt->ipo = BEZT_IPO_QUART;
1294 }
1295 return 0;
1296 }
1297
set_bezt_quint(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1298 static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1299 {
1300 if (bezt->f2 & SELECT) {
1301 bezt->ipo = BEZT_IPO_QUINT;
1302 }
1303 return 0;
1304 }
1305
set_bezt_sine(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1306 static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1307 {
1308 if (bezt->f2 & SELECT) {
1309 bezt->ipo = BEZT_IPO_SINE;
1310 }
1311 return 0;
1312 }
1313
1314 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
1315 /* ANIM_editkeyframes_ipocurve_ipotype() ! */
ANIM_editkeyframes_ipo(short mode)1316 KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
1317 {
1318 switch (mode) {
1319 /* interpolation */
1320 case BEZT_IPO_CONST: /* constant */
1321 return set_bezt_constant;
1322 case BEZT_IPO_LIN: /* linear */
1323 return set_bezt_linear;
1324
1325 /* easing */
1326 case BEZT_IPO_BACK:
1327 return set_bezt_back;
1328 case BEZT_IPO_BOUNCE:
1329 return set_bezt_bounce;
1330 case BEZT_IPO_CIRC:
1331 return set_bezt_circle;
1332 case BEZT_IPO_CUBIC:
1333 return set_bezt_cubic;
1334 case BEZT_IPO_ELASTIC:
1335 return set_bezt_elastic;
1336 case BEZT_IPO_EXPO:
1337 return set_bezt_expo;
1338 case BEZT_IPO_QUAD:
1339 return set_bezt_quad;
1340 case BEZT_IPO_QUART:
1341 return set_bezt_quart;
1342 case BEZT_IPO_QUINT:
1343 return set_bezt_quint;
1344 case BEZT_IPO_SINE:
1345 return set_bezt_sine;
1346
1347 default: /* bezier */
1348 return set_bezt_bezier;
1349 }
1350 }
1351
1352 /* ------- */
1353
set_keytype_keyframe(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1354 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1355 {
1356 if (bezt->f2 & SELECT) {
1357 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_KEYFRAME;
1358 }
1359 return 0;
1360 }
1361
set_keytype_breakdown(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1362 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1363 {
1364 if (bezt->f2 & SELECT) {
1365 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN;
1366 }
1367 return 0;
1368 }
1369
set_keytype_extreme(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1370 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1371 {
1372 if (bezt->f2 & SELECT) {
1373 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME;
1374 }
1375 return 0;
1376 }
1377
set_keytype_jitter(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1378 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1379 {
1380 if (bezt->f2 & SELECT) {
1381 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER;
1382 }
1383 return 0;
1384 }
1385
set_keytype_moving_hold(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1386 static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1387 {
1388 if (bezt->f2 & SELECT) {
1389 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
1390 }
1391 return 0;
1392 }
1393
1394 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
ANIM_editkeyframes_keytype(short mode)1395 KeyframeEditFunc ANIM_editkeyframes_keytype(short mode)
1396 {
1397 switch (mode) {
1398 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
1399 return set_keytype_breakdown;
1400
1401 case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
1402 return set_keytype_extreme;
1403
1404 case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
1405 return set_keytype_jitter;
1406
1407 case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
1408 return set_keytype_moving_hold;
1409
1410 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
1411 default:
1412 return set_keytype_keyframe;
1413 }
1414 }
1415
1416 /* ------- */
1417
set_easingtype_easein(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1418 static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1419 {
1420 if (bezt->f2 & SELECT) {
1421 bezt->easing = BEZT_IPO_EASE_IN;
1422 }
1423 return 0;
1424 }
1425
set_easingtype_easeout(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1426 static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1427 {
1428 if (bezt->f2 & SELECT) {
1429 bezt->easing = BEZT_IPO_EASE_OUT;
1430 }
1431 return 0;
1432 }
1433
set_easingtype_easeinout(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1434 static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1435 {
1436 if (bezt->f2 & SELECT) {
1437 bezt->easing = BEZT_IPO_EASE_IN_OUT;
1438 }
1439 return 0;
1440 }
1441
set_easingtype_easeauto(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1442 static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1443 {
1444 if (bezt->f2 & SELECT) {
1445 bezt->easing = BEZT_IPO_EASE_AUTO;
1446 }
1447 return 0;
1448 }
1449
1450 /* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
ANIM_editkeyframes_easing(short mode)1451 KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
1452 {
1453 switch (mode) {
1454 case BEZT_IPO_EASE_IN: /* ease in */
1455 return set_easingtype_easein;
1456
1457 case BEZT_IPO_EASE_OUT: /* ease out */
1458 return set_easingtype_easeout;
1459
1460 case BEZT_IPO_EASE_IN_OUT: /* both */
1461 return set_easingtype_easeinout;
1462
1463 default: /* auto */
1464 return set_easingtype_easeauto;
1465 }
1466 }
1467
1468 /* ******************************************* */
1469 /* Selection */
1470
select_bezier_add(KeyframeEditData * ked,BezTriple * bezt)1471 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
1472 {
1473 /* Only act on visible items, so check handle visibility state. */
1474 const bool handles_visible = ked && ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ?
1475 (BEZT_ISSEL_ANY(bezt)) :
1476 true);
1477
1478 /* if we've got info on what to select, use it, otherwise select all */
1479 if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES) && handles_visible) {
1480 if (ked->curflags & KEYFRAME_OK_KEY) {
1481 bezt->f2 |= SELECT;
1482 }
1483 if (ked->curflags & KEYFRAME_OK_H1) {
1484 bezt->f1 |= SELECT;
1485 }
1486 if (ked->curflags & KEYFRAME_OK_H2) {
1487 bezt->f3 |= SELECT;
1488 }
1489 }
1490 else {
1491 BEZT_SEL_ALL(bezt);
1492 }
1493
1494 return 0;
1495 }
1496
select_bezier_subtract(KeyframeEditData * ked,BezTriple * bezt)1497 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
1498 {
1499 /* Only act on visible items, so check handle visibility state. */
1500 const bool handles_visible = ked && ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ?
1501 (BEZT_ISSEL_ANY(bezt)) :
1502 true);
1503
1504 /* if we've got info on what to deselect, use it, otherwise deselect all */
1505 if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES) && handles_visible) {
1506 if (ked->curflags & KEYFRAME_OK_KEY) {
1507 bezt->f2 &= ~SELECT;
1508 }
1509 if (ked->curflags & KEYFRAME_OK_H1) {
1510 bezt->f1 &= ~SELECT;
1511 }
1512 if (ked->curflags & KEYFRAME_OK_H2) {
1513 bezt->f3 &= ~SELECT;
1514 }
1515 }
1516 else {
1517 BEZT_DESEL_ALL(bezt);
1518 }
1519
1520 return 0;
1521 }
1522
select_bezier_invert(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1523 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1524 {
1525 /* Invert the selection for the whole bezier triple */
1526 bezt->f2 ^= SELECT;
1527 if (bezt->f2 & SELECT) {
1528 bezt->f1 |= SELECT;
1529 bezt->f3 |= SELECT;
1530 }
1531 else {
1532 bezt->f1 &= ~SELECT;
1533 bezt->f3 &= ~SELECT;
1534 }
1535 return 0;
1536 }
1537
ANIM_editkeyframes_select(short selectmode)1538 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
1539 {
1540 switch (selectmode) {
1541 case SELECT_ADD: /* add */
1542 return select_bezier_add;
1543 case SELECT_SUBTRACT: /* subtract */
1544 return select_bezier_subtract;
1545 case SELECT_INVERT: /* invert */
1546 return select_bezier_invert;
1547 default: /* replace (need to clear all, then add) */
1548 return select_bezier_add;
1549 }
1550 }
1551
1552 /* ******************************************* */
1553 /* Selection Maps */
1554
1555 /* Selection maps are simply fancy names for char arrays that store on/off
1556 * info for whether the selection status. The main purpose for these is to
1557 * allow extra info to be tagged to the keyframes without influencing their
1558 * values or having to be removed later.
1559 */
1560
1561 /* ----------- */
1562
selmap_build_bezier_more(KeyframeEditData * ked,BezTriple * bezt)1563 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
1564 {
1565 FCurve *fcu = ked->fcu;
1566 char *map = ked->data;
1567 int i = ked->curIndex;
1568
1569 /* if current is selected, just make sure it stays this way */
1570 if (BEZT_ISSEL_ANY(bezt)) {
1571 map[i] = 1;
1572 return 0;
1573 }
1574
1575 /* if previous is selected, that means that selection should extend across */
1576 if (i > 0) {
1577 BezTriple *prev = bezt - 1;
1578
1579 if (BEZT_ISSEL_ANY(prev)) {
1580 map[i] = 1;
1581 return 0;
1582 }
1583 }
1584
1585 /* if next is selected, that means that selection should extend across */
1586 if (i < (fcu->totvert - 1)) {
1587 BezTriple *next = bezt + 1;
1588
1589 if (BEZT_ISSEL_ANY(next)) {
1590 map[i] = 1;
1591 return 0;
1592 }
1593 }
1594
1595 return 0;
1596 }
1597
selmap_build_bezier_less(KeyframeEditData * ked,BezTriple * bezt)1598 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
1599 {
1600 FCurve *fcu = ked->fcu;
1601 char *map = ked->data;
1602 int i = ked->curIndex;
1603
1604 /* if current is selected, check the left/right keyframes
1605 * since it might need to be deselected (but otherwise no)
1606 */
1607 if (BEZT_ISSEL_ANY(bezt)) {
1608 /* if previous is not selected, we're on the tip of an iceberg */
1609 if (i > 0) {
1610 BezTriple *prev = bezt - 1;
1611
1612 if (BEZT_ISSEL_ANY(prev) == 0) {
1613 return 0;
1614 }
1615 }
1616 else if (i == 0) {
1617 /* current keyframe is selected at an endpoint, so should get deselected */
1618 return 0;
1619 }
1620
1621 /* if next is not selected, we're on the tip of an iceberg */
1622 if (i < (fcu->totvert - 1)) {
1623 BezTriple *next = bezt + 1;
1624
1625 if (BEZT_ISSEL_ANY(next) == 0) {
1626 return 0;
1627 }
1628 }
1629 else if (i == (fcu->totvert - 1)) {
1630 /* current keyframe is selected at an endpoint, so should get deselected */
1631 return 0;
1632 }
1633
1634 /* if we're still here, that means that keyframe should remain untouched */
1635 map[i] = 1;
1636 }
1637
1638 return 0;
1639 }
1640
1641 /* Get callback for building selection map */
ANIM_editkeyframes_buildselmap(short mode)1642 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
1643 {
1644 switch (mode) {
1645 case SELMAP_LESS: /* less */
1646 return selmap_build_bezier_less;
1647
1648 case SELMAP_MORE: /* more */
1649 default:
1650 return selmap_build_bezier_more;
1651 }
1652 }
1653
1654 /* ----------- */
1655
1656 /* flush selection map values to the given beztriple */
bezt_selmap_flush(KeyframeEditData * ked,BezTriple * bezt)1657 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
1658 {
1659 const char *map = ked->data;
1660 short on = map[ked->curIndex];
1661
1662 /* select or deselect based on whether the map allows it or not */
1663 if (on) {
1664 BEZT_SEL_ALL(bezt);
1665 }
1666 else {
1667 BEZT_DESEL_ALL(bezt);
1668 }
1669
1670 return 0;
1671 }
1672